From 681804ba1ab71e59009c3bb0acee2a69e405f20b Mon Sep 17 00:00:00 2001 From: Norman Soetbeer Date: Sun, 11 Oct 2020 13:23:06 +0200 Subject: [PATCH 001/146] [HttpFoundation] Fix Range Requests --- .../HttpFoundation/BinaryFileResponse.php | 43 ++++++++++--------- .../Tests/BinaryFileResponseTest.php | 25 ++++++++++- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index c2f66d6952ab2..0a43b8ac71c3f 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -239,33 +239,36 @@ public function prepare(Request $request) $this->headers->set($type, $path); $this->maxlen = 0; } - } elseif ($request->headers->has('Range')) { + } elseif ($request->headers->has('Range') && $request->isMethod('GET')) { // Process the range headers. if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); - list($start, $end) = explode('-', substr($range, 6), 2) + [0]; + if (0 === strpos($range, 'bytes=')) { + list($start, $end) = explode('-', substr($range, 6), 2) + [0]; - $end = ('' === $end) ? $fileSize - 1 : (int) $end; + $end = ('' === $end) ? $fileSize - 1 : (int) $end; - if ('' === $start) { - $start = $fileSize - $end; - $end = $fileSize - 1; - } else { - $start = (int) $start; - } + if ('' === $start) { + $start = $fileSize - $end; + $end = $fileSize - 1; + } else { + $start = (int) $start; + } - if ($start <= $end) { - if ($start < 0 || $end > $fileSize - 1) { - $this->setStatusCode(416); - $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); - } elseif (0 !== $start || $end !== $fileSize - 1) { - $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; - $this->offset = $start; - - $this->setStatusCode(206); - $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); - $this->headers->set('Content-Length', $end - $start + 1); + if ($start <= $end) { + $end = min($end, $fileSize - 1); + if ($start < 0 || $start > $end) { + $this->setStatusCode(416); + $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); + } elseif ($end - $start < $fileSize - 1) { + $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; + $this->offset = $start; + + $this->setStatusCode(206); + $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); + $this->headers->set('Content-Length', $end - $start + 1); + } } } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 31916fc7d6876..38cc84420c5b5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -149,6 +149,7 @@ public function provideRanges() ['bytes=30-', 30, 5, 'bytes 30-34/35'], ['bytes=30-30', 30, 1, 'bytes 30-30/35'], ['bytes=30-34', 30, 5, 'bytes 30-34/35'], + ['bytes=30-40', 30, 5, 'bytes 30-34/35'], ]; } @@ -203,9 +204,31 @@ public function provideFullFileRanges() // Syntactical invalid range-request should also return the full resource ['bytes=20-10'], ['bytes=50-40'], + // range units other than bytes must be ignored + ['unknown=10-20'], ]; } + public function testRangeOnPostMethod() + { + $request = Request::create('/', 'POST'); + $request->headers->set('Range', 'bytes=10-20'); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); + + $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); + $data = fread($file, 35); + fclose($file); + + $this->expectOutputString($data); + $response = clone $response; + $response->prepare($request); + $response->sendContent(); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('35', $response->headers->get('Content-Length')); + $this->assertNull($response->headers->get('Content-Range')); + } + public function testUnpreparedResponseSendsFullFile() { $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200); @@ -242,7 +265,7 @@ public function provideInvalidRanges() { return [ ['bytes=-40'], - ['bytes=30-40'], + ['bytes=40-50'], ]; } From 8c4ecc313bfa2a95f8c1b15652c06b6d88cfeb68 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 14 Oct 2020 21:27:47 +0200 Subject: [PATCH 002/146] Bump Symfony version to 5.2.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 3ba3cd9623708..ad9a4b2d78a5b 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,12 +74,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '5.2.0-BETA2'; + const VERSION = '5.2.0-DEV'; const VERSION_ID = 50200; const MAJOR_VERSION = 5; const MINOR_VERSION = 2; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'BETA2'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '07/2021'; const END_OF_LIFE = '07/2021'; From 08c080600acfc642819abc3d6a83071eb9ff2c88 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 14 Oct 2020 21:52:57 +0200 Subject: [PATCH 003/146] Add wouterj as codeowner for Security related packages --- .github/CODEOWNERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6a9ac46efac81..84d3d21e303bd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -35,6 +35,11 @@ /src/Symfony/Bridge/Doctrine/PropertyInfo/ @dunglas # Serializer /src/Symfony/Component/Serializer/ @dunglas +# Security +/src/Symfony/Bridge/Doctrine/Security/ @wouterj +/src/Symfony/Bundle/SecurityBundle/ @wouterj +/src/Symfony/Component/Security/ @wouterj +/src/Symfony/Component/Ldap/Security/ @wouterj # TwigBundle /src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @yceruto # WebLink From a2ab55407bf8c16540f55dd5c021014282b531b3 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 15 Oct 2020 00:44:23 +0200 Subject: [PATCH 004/146] Add myself to CODEOWNERS for Security and Console --- .github/CODEOWNERS | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 84d3d21e303bd..37b2dbfcdc0e6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,5 @@ # Console +/src/Symfony/Component/Console/ @chalasr /src/Symfony/Component/Console/Logger/ConsoleLogger.php @dunglas # DependencyInjection /src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @dunglas @@ -36,10 +37,10 @@ # Serializer /src/Symfony/Component/Serializer/ @dunglas # Security -/src/Symfony/Bridge/Doctrine/Security/ @wouterj -/src/Symfony/Bundle/SecurityBundle/ @wouterj -/src/Symfony/Component/Security/ @wouterj -/src/Symfony/Component/Ldap/Security/ @wouterj +/src/Symfony/Bridge/Doctrine/Security/ @wouterj @chalasr +/src/Symfony/Bundle/SecurityBundle/ @wouterj @chalasr +/src/Symfony/Component/Security/ @wouterj @chalasr +/src/Symfony/Component/Ldap/Security/ @wouterj @chalasr # TwigBundle /src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @yceruto # WebLink From 40ea90ef6bd41cf48cc195747d3ee2622e1dfb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 15 Oct 2020 01:04:22 +0200 Subject: [PATCH 005/146] Deeprecate lock service --- .../DependencyInjection/FrameworkExtension.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index eb6aeb2c323b4..2c92a1a748b2d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1689,16 +1689,16 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont $lockDefinition->setPublic(false); $lockDefinition->setFactory([new Reference('lock.'.$resourceName.'.factory'), 'createLock']); $lockDefinition->setArguments([$resourceName]); - $container->setDefinition('lock.'.$resourceName, $lockDefinition); + $container->setDefinition('lock.'.$resourceName, $lockDefinition)->setDeprecated('symfony/framework-bundle', '5.2', 'The "%service_id%" service is deprecated, use "lock.'.$resourceName.'.factory" instead.'); // provide alias for default resource if ('default' === $resourceName) { $container->setAlias('lock.store', new Alias('lock.'.$resourceName.'.store', false)); $container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false)); - $container->setAlias('lock', new Alias('lock.'.$resourceName, false)); + $container->setAlias('lock', (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.factory" instead.')); $container->setAlias(PersistingStoreInterface::class, new Alias('lock.store', false)); $container->setAlias(LockFactory::class, new Alias('lock.factory', false)); - $container->setAlias(LockInterface::class, new Alias('lock', false)); + $container->setAlias(LockInterface::class, (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.'" instead.')); } else { $container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistingStoreInterface::class, $resourceName.'.lock.store'); $container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory'); From 4a63308fb356bdcc9820e12698cc1e9c78fc140b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 15 Oct 2020 01:12:09 +0200 Subject: [PATCH 006/146] Add missing use statement --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cfb5d0728a4dc..60302152b10e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -74,6 +74,7 @@ use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\PersistingStoreInterface; use Symfony\Component\Lock\Store\StoreFactory; +use Symfony\Component\Lock\StoreInterface; use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory; use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory; use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory; From c6d3b703153947f7bb6879f63b3fea6f61ad2514 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 14 Oct 2020 11:18:30 +0200 Subject: [PATCH 007/146] [RateLimiter] Adding SlidingWindow algorithm --- .../DependencyInjection/Configuration.php | 4 +- .../Exception/InvalidIntervalException.php | 21 +++ src/Symfony/Component/RateLimiter/Limiter.php | 5 +- .../Component/RateLimiter/SlidingWindow.php | 125 ++++++++++++++++++ .../RateLimiter/SlidingWindowLimiter.php | 104 +++++++++++++++ .../Tests/SlidingWindowLimiterTest.php | 57 ++++++++ .../RateLimiter/Tests/SlidingWindowTest.php | 39 ++++++ 7 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/RateLimiter/Exception/InvalidIntervalException.php create mode 100644 src/Symfony/Component/RateLimiter/SlidingWindow.php create mode 100644 src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php create mode 100644 src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php create mode 100644 src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0d4ee4f797528..179bc24b51321 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1817,14 +1817,14 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode) ->enumNode('strategy') ->info('The rate limiting algorithm to use for this rate') ->isRequired() - ->values(['fixed_window', 'token_bucket']) + ->values(['fixed_window', 'token_bucket', 'sliding_window']) ->end() ->integerNode('limit') ->info('The maximum allowed hits in a fixed interval or burst') ->isRequired() ->end() ->scalarNode('interval') - ->info('Configures the fixed interval if "strategy" is set to "fixed_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).') + ->info('Configures the fixed interval if "strategy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).') ->end() ->arrayNode('rate') ->info('Configures the fill rate if "strategy" is set to "token_bucket"') diff --git a/src/Symfony/Component/RateLimiter/Exception/InvalidIntervalException.php b/src/Symfony/Component/RateLimiter/Exception/InvalidIntervalException.php new file mode 100644 index 0000000000000..02b5c810e8278 --- /dev/null +++ b/src/Symfony/Component/RateLimiter/Exception/InvalidIntervalException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter\Exception; + +/** + * @author Tobias Nyholm + * + * @experimental in 5.2 + */ +class InvalidIntervalException extends \LogicException +{ +} diff --git a/src/Symfony/Component/RateLimiter/Limiter.php b/src/Symfony/Component/RateLimiter/Limiter.php index 3898e89018795..61018ab807372 100644 --- a/src/Symfony/Component/RateLimiter/Limiter.php +++ b/src/Symfony/Component/RateLimiter/Limiter.php @@ -51,8 +51,11 @@ public function create(?string $key = null): LimiterInterface case 'fixed_window': return new FixedWindowLimiter($id, $this->config['limit'], $this->config['interval'], $this->storage, $lock); + case 'sliding_window': + return new SlidingWindowLimiter($id, $this->config['limit'], $this->config['interval'], $this->storage, $lock); + default: - throw new \LogicException(sprintf('Limiter strategy "%s" does not exists, it must be either "token_bucket" or "fixed_window".', $this->config['strategy'])); + throw new \LogicException(sprintf('Limiter strategy "%s" does not exists, it must be either "token_bucket", "sliding_window" or "fixed_window".', $this->config['strategy'])); } } diff --git a/src/Symfony/Component/RateLimiter/SlidingWindow.php b/src/Symfony/Component/RateLimiter/SlidingWindow.php new file mode 100644 index 0000000000000..73359dc41b76b --- /dev/null +++ b/src/Symfony/Component/RateLimiter/SlidingWindow.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter; + +use Symfony\Component\RateLimiter\Exception\InvalidIntervalException; + +/** + * @author Tobias Nyholm + * + * @experimental in 5.2 + */ +final class SlidingWindow implements LimiterStateInterface +{ + /** + * @var string + */ + private $id; + + /** + * @var int + */ + private $hitCount = 0; + + /** + * @var int + */ + private $hitCountForLastWindow = 0; + + /** + * @var int how long a time frame is + */ + private $intervalInSeconds; + + /** + * @var int the unix timestamp when the current window ends + */ + private $windowEndAt; + + /** + * @var bool true if this window has been cached + */ + private $cached = true; + + public function __construct(string $id, int $intervalInSeconds) + { + if ($intervalInSeconds < 1) { + throw new InvalidIntervalException(sprintf('The interval must be positive integer, "%d" given.', $intervalInSeconds)); + } + $this->id = $id; + $this->intervalInSeconds = $intervalInSeconds; + $this->windowEndAt = time() + $intervalInSeconds; + $this->cached = false; + } + + public static function createFromPreviousWindow(self $window, int $intervalInSeconds): self + { + $new = new self($window->id, $intervalInSeconds); + $new->hitCountForLastWindow = $window->hitCount; + $new->windowEndAt = $window->windowEndAt + $intervalInSeconds; + + return $new; + } + + /** + * @internal + */ + public function __sleep(): array + { + // $cached is not serialized, it should only be set + // upon first creation of the Window. + return ['id', 'hitCount', 'intervalInSeconds', 'hitCountForLastWindow', 'windowEndAt']; + } + + public function getId(): string + { + return $this->id; + } + + /** + * Store for the rest of this time frame and next. + */ + public function getExpirationTime(): ?int + { + if ($this->cached) { + return null; + } + + return 2 * $this->intervalInSeconds; + } + + public function isExpired(): bool + { + return time() > $this->windowEndAt; + } + + public function add(int $hits = 1) + { + $this->hitCount += $hits; + } + + /** + * Calculates the sliding window number of request. + */ + public function getHitCount(): int + { + $startOfWindow = $this->windowEndAt - $this->intervalInSeconds; + $percentOfCurrentTimeFrame = (time() - $startOfWindow) / $this->intervalInSeconds; + + return (int) floor($this->hitCountForLastWindow * (1 - $percentOfCurrentTimeFrame) + $this->hitCount); + } + + public function getRetryAfter(): \DateTimeImmutable + { + return \DateTimeImmutable::createFromFormat('U', $this->windowEndAt); + } +} diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php new file mode 100644 index 0000000000000..fbc6a41958d5a --- /dev/null +++ b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter; + +use Symfony\Component\Lock\LockInterface; +use Symfony\Component\Lock\NoLock; +use Symfony\Component\RateLimiter\Storage\StorageInterface; +use Symfony\Component\RateLimiter\Util\TimeUtil; + +/** + * The sliding window algorithm will look at your last window and the current one. + * It is good algorithm to reduce bursts. + * + * Example: + * Last time window we did 8 hits. We are currently 25% into + * the current window. We have made 3 hits in the current window so far. + * That means our sliding window hit count is (75% * 8) + 3 = 9. + * + * @author Tobias Nyholm + * + * @experimental in 5.2 + */ +final class SlidingWindowLimiter implements LimiterInterface +{ + /** + * @var string + */ + private $id; + + /** + * @var int + */ + private $limit; + + /** + * @var \DateInterval + */ + private $interval; + + /** + * @var StorageInterface + */ + private $storage; + + /** + * @var LockInterface|null + */ + private $lock; + + use ResetLimiterTrait; + + public function __construct(string $id, int $limit, \DateInterval $interval, StorageInterface $storage, ?LockInterface $lock = null) + { + $this->storage = $storage; + $this->lock = $lock ?? new NoLock(); + $this->id = $id; + $this->limit = $limit; + $this->interval = TimeUtil::dateIntervalToSeconds($interval); + } + + /** + * {@inheritdoc} + */ + public function consume(int $tokens = 1): Limit + { + $this->lock->acquire(true); + + try { + $window = $this->storage->fetch($this->id); + if (!$window instanceof SlidingWindow) { + $window = new SlidingWindow($this->id, $this->interval); + } elseif ($window->isExpired()) { + $window = SlidingWindow::createFromPreviousWindow($window, $this->interval); + } + + $hitCount = $window->getHitCount(); + $availableTokens = $this->getAvailableTokens($hitCount); + if ($availableTokens < $tokens) { + return new Limit($availableTokens, $window->getRetryAfter(), false); + } + + $window->add($tokens); + $this->storage->save($window); + + return new Limit($this->getAvailableTokens($window->getHitCount()), $window->getRetryAfter(), true); + } finally { + $this->lock->release(); + } + } + + private function getAvailableTokens(int $hitCount): int + { + return $this->limit - $hitCount; + } +} diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php new file mode 100644 index 0000000000000..589d4e5550719 --- /dev/null +++ b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ClockMock; +use Symfony\Component\RateLimiter\SlidingWindowLimiter; +use Symfony\Component\RateLimiter\Storage\InMemoryStorage; + +/** + * @group time-sensitive + */ +class SlidingWindowLimiterTest extends TestCase +{ + private $storage; + + protected function setUp(): void + { + $this->storage = new InMemoryStorage(); + + ClockMock::register(InMemoryStorage::class); + } + + public function testConsume() + { + $limiter = $this->createLimiter(); + + $limiter->consume(8); + sleep(15); + + $limit = $limiter->consume(); + $this->assertTrue($limit->isAccepted()); + + // We are 25% into the new window + $limit = $limiter->consume(5); + $this->assertFalse($limit->isAccepted()); + $this->assertEquals(3, $limit->getRemainingTokens()); + + sleep(13); + $limit = $limiter->consume(10); + $this->assertTrue($limit->isAccepted()); + } + + private function createLimiter(): SlidingWindowLimiter + { + return new SlidingWindowLimiter('test', 10, new \DateInterval('PT12S'), $this->storage); + } +} diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php new file mode 100644 index 0000000000000..0bdeb499c51b5 --- /dev/null +++ b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\RateLimiter\Exception\InvalidIntervalException; +use Symfony\Component\RateLimiter\SlidingWindow; + +class SlidingWindowTest extends TestCase +{ + public function testGetExpirationTime() + { + $window = new SlidingWindow('foo', 10); + $this->assertSame(2 * 10, $window->getExpirationTime()); + $this->assertSame(2 * 10, $window->getExpirationTime()); + + $data = serialize($window); + $cachedWindow = unserialize($data); + $this->assertNull($cachedWindow->getExpirationTime()); + + $new = SlidingWindow::createFromPreviousWindow($cachedWindow, 15); + $this->assertSame(2 * 15, $new->getExpirationTime()); + } + + public function testInvalidInterval() + { + $this->expectException(InvalidIntervalException::class); + new SlidingWindow('foo', 0); + } +} From db392d244119447be886c25dcb2d4329ce7c8260 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 15 Oct 2020 10:06:30 +0200 Subject: [PATCH 008/146] Fix: Typo --- src/Symfony/Component/RateLimiter/SlidingWindow.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/SlidingWindow.php b/src/Symfony/Component/RateLimiter/SlidingWindow.php index 73359dc41b76b..53b3f89293ae1 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindow.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindow.php @@ -76,7 +76,7 @@ public static function createFromPreviousWindow(self $window, int $intervalInSec public function __sleep(): array { // $cached is not serialized, it should only be set - // upon first creation of the Window. + // upon first creation of the window. return ['id', 'hitCount', 'intervalInSeconds', 'hitCountForLastWindow', 'windowEndAt']; } From 2514cf1c1d197ed0297006ed1ab88c8e08b5c972 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 15 Oct 2020 10:20:12 +0200 Subject: [PATCH 009/146] [FrameworkBundle] fix config declaration of http_cache option --- .../FrameworkBundle/DependencyInjection/Configuration.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0d4ee4f797528..5e4e336cfcbe0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -218,6 +218,7 @@ private function addHttpCacheSection(ArrayNodeDefinition $rootNode) ->arrayNode('http_cache') ->info('HTTP cache configuration') ->canBeEnabled() + ->fixXmlConfig('private_header') ->children() ->booleanNode('debug')->defaultValue('%kernel.debug%')->end() ->enumNode('trace_level') @@ -227,8 +228,6 @@ private function addHttpCacheSection(ArrayNodeDefinition $rootNode) ->integerNode('default_ttl')->end() ->arrayNode('private_headers') ->performNoDeepMerging() - ->requiresAtLeastOneElement() - ->fixXmlConfig('private_header') ->scalarPrototype()->end() ->end() ->booleanNode('allow_reload')->end() From 394a69485602203467a6e94e66f536e48ab4127f Mon Sep 17 00:00:00 2001 From: Maxime Aknin Date: Thu, 15 Oct 2020 10:23:16 +0200 Subject: [PATCH 010/146] Fix Reflection file name with eval()\'d code remove eval()\'d code from lineage --- src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 1d4017f4c22e2..8605d755b31c6 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -374,6 +374,9 @@ private function collectLineage($class, array &$lineage) return; } $file = $r->getFileName(); + if (') : eval()\'d code' === substr($file, -17)) { + $file = substr($file, 0, strrpos($file, '(', -17)); + } if (!$file || $this->doExport($file) === $exportedFile = $this->export($file)) { return; } From f9ddc5c1474e5a9f53e01af0f0b2a8797aff8931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 15 Oct 2020 11:48:15 +0200 Subject: [PATCH 011/146] Missing Changelog for deprecating services --- UPGRADE-5.2.md | 1 + UPGRADE-6.0.md | 1 + src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/UPGRADE-5.2.md b/UPGRADE-5.2.md index e5e486972774a..ff29d10c8cfbe 100644 --- a/UPGRADE-5.2.md +++ b/UPGRADE-5.2.md @@ -15,6 +15,7 @@ FrameworkBundle keep cache namespaces separated by environment of the app. The `%kernel.container_class%` (which includes the environment) used to be added by default to the seed, which is not the case anymore. This allows sharing caches between apps or different environments. + * Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. Form ---- diff --git a/UPGRADE-6.0.md b/UPGRADE-6.0.md index 69db8ccddbb48..1bedeaad74a51 100644 --- a/UPGRADE-6.0.md +++ b/UPGRADE-6.0.md @@ -58,6 +58,7 @@ FrameworkBundle * Removed `session.attribute_bag` service and `session.flash_bag` service. * The `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`, `cache_clearer`, `filesystem` and `validator` services are now private. + * Removed the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. HttpFoundation -------------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 05e6608be8173..0d12982902503 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -14,6 +14,7 @@ CHANGELOG * added `assertCheckboxChecked()` and `assertCheckboxNotChecked()` in `WebTestCase` * added `assertFormValue()` and `assertNoFormValue()` in `WebTestCase` * Added "--as-tree=3" option to `translation:update` command to dump messages as a tree-like structure. The given value defines the level where to switch to inline YAML + * Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. 5.1.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 2c92a1a748b2d..3a7ab77a563bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1702,7 +1702,7 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont } else { $container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistingStoreInterface::class, $resourceName.'.lock.store'); $container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory'); - $container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock'); + $container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock')->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.' $'.$resourceName.'LockFactory" instead.'); } } } From 61290d5aa41b3fb0de6e71a9fb456c6e2eabebba Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 15 Oct 2020 14:02:47 +0200 Subject: [PATCH 012/146] [HttpClient] added `extra.trace_content` option to `TraceableHttpClient` to prevent it from keeping the content in memory --- src/Symfony/Component/HttpClient/CHANGELOG.md | 1 + .../HttpClient/Response/TraceableResponse.php | 8 ++++++++ .../Tests/TraceableHttpClientTest.php | 19 +++++++++++++++++-- .../HttpClient/TraceableHttpClient.php | 5 +++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CHANGELOG.md b/src/Symfony/Component/HttpClient/CHANGELOG.md index 3ea81aafccc53..f25989e168396 100644 --- a/src/Symfony/Component/HttpClient/CHANGELOG.md +++ b/src/Symfony/Component/HttpClient/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * added `EventSourceHttpClient` a Server-Sent events stream implementing the [EventSource specification](https://www.w3.org/TR/eventsource/#eventsource) * added option "extra.curl" to allow setting additional curl options in `CurlHttpClient` * added `RetryableHttpClient` to automatically retry failed HTTP requests. + * added `extra.trace_content` option to `TraceableHttpClient` to prevent it from keeping the content in memory 5.1.0 ----- diff --git a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php index e42b62a6a42af..ea9afa43b1ef1 100644 --- a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php +++ b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php @@ -52,6 +52,10 @@ public function getHeaders(bool $throw = true): array public function getContent(bool $throw = true): string { + if (false === $this->content) { + return $this->response->getContent($throw); + } + $this->content = $this->response->getContent(false); if ($throw) { @@ -63,6 +67,10 @@ public function getContent(bool $throw = true): string public function toArray(bool $throw = true): array { + if (false === $this->content) { + return $this->response->toArray($throw); + } + $this->content = $this->response->toArray(false); if ($throw) { diff --git a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php index 9b6752f7b62cd..94e557cd893cf 100755 --- a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php @@ -30,14 +30,14 @@ public function testItTracesRequest() { $httpClient = $this->getMockBuilder(HttpClientInterface::class)->getMock(); $httpClient - ->expects($this->once()) + ->expects($this->any()) ->method('request') ->with( 'GET', '/foo/bar', $this->callback(function ($subject) { $onprogress = $subject['on_progress']; - unset($subject['on_progress']); + unset($subject['on_progress'], $subject['extra']); $this->assertEquals(['options1' => 'foo'], $subject); return true; @@ -45,8 +45,11 @@ public function testItTracesRequest() ) ->willReturn(MockResponse::fromRequest('GET', '/foo/bar', ['options1' => 'foo'], new MockResponse('hello'))) ; + $sut = new TraceableHttpClient($httpClient); + $sut->request('GET', '/foo/bar', ['options1' => 'foo'])->getContent(); + $this->assertCount(1, $tracedRequests = $sut->getTracedRequests()); $actualTracedRequest = $tracedRequests[0]; $this->assertEquals([ @@ -56,6 +59,18 @@ public function testItTracesRequest() 'info' => [], 'content' => 'hello', ], $actualTracedRequest); + + $sut->request('GET', '/foo/bar', ['options1' => 'foo', 'extra' => ['trace_content' => false]])->getContent(); + + $this->assertCount(2, $tracedRequests = $sut->getTracedRequests()); + $actualTracedRequest = $tracedRequests[1]; + $this->assertEquals([ + 'method' => 'GET', + 'url' => '/foo/bar', + 'options' => ['options1' => 'foo', 'extra' => ['trace_content' => false]], + 'info' => [], + 'content' => null, + ], $actualTracedRequest); } public function testItCollectsInfoOnRealRequest() diff --git a/src/Symfony/Component/HttpClient/TraceableHttpClient.php b/src/Symfony/Component/HttpClient/TraceableHttpClient.php index b70c544a66b6f..a061fef7ea80c 100644 --- a/src/Symfony/Component/HttpClient/TraceableHttpClient.php +++ b/src/Symfony/Component/HttpClient/TraceableHttpClient.php @@ -49,6 +49,11 @@ public function request(string $method, string $url, array $options = []): Respo ]; $onProgress = $options['on_progress'] ?? null; + if (false === ($options['extra']['trace_content'] ?? true)) { + unset($content); + $content = false; + } + $options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use (&$traceInfo, $onProgress) { $traceInfo = $info; From e7ffd5d2e795b8896cc853ae3884df92f385ee5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 15 Oct 2020 10:19:08 +0200 Subject: [PATCH 013/146] Reset Key lifetime time in semaphore --- src/Symfony/Component/Semaphore/Key.php | 5 +++++ src/Symfony/Component/Semaphore/Semaphore.php | 2 ++ .../Semaphore/Tests/SemaphoreTest.php | 20 +++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/Symfony/Component/Semaphore/Key.php b/src/Symfony/Component/Semaphore/Key.php index 741b795f18c01..b2ba8db50acea 100644 --- a/src/Symfony/Component/Semaphore/Key.php +++ b/src/Symfony/Component/Semaphore/Key.php @@ -80,6 +80,11 @@ public function getState(string $stateKey) return $this->state[$stateKey]; } + public function resetLifetime(): void + { + $this->expiringTime = null; + } + public function reduceLifetime(float $ttlInSeconds) { $newTime = microtime(true) + $ttlInSeconds; diff --git a/src/Symfony/Component/Semaphore/Semaphore.php b/src/Symfony/Component/Semaphore/Semaphore.php index 931d675a929cb..a65e2bc289996 100644 --- a/src/Symfony/Component/Semaphore/Semaphore.php +++ b/src/Symfony/Component/Semaphore/Semaphore.php @@ -66,6 +66,7 @@ public function __destruct() public function acquire(): bool { try { + $this->key->resetLifetime(); $this->store->save($this->key, $this->ttlInSecond); $this->key->reduceLifetime($this->ttlInSecond); $this->dirty = true; @@ -97,6 +98,7 @@ public function refresh(?float $ttlInSecond = null) } try { + $this->key->resetLifetime(); $this->store->putOffExpiration($this->key, $ttlInSecond); $this->key->reduceLifetime($ttlInSecond); diff --git a/src/Symfony/Component/Semaphore/Tests/SemaphoreTest.php b/src/Symfony/Component/Semaphore/Tests/SemaphoreTest.php index 9efe71b9c3e65..556c8aad2396b 100644 --- a/src/Symfony/Component/Semaphore/Tests/SemaphoreTest.php +++ b/src/Symfony/Component/Semaphore/Tests/SemaphoreTest.php @@ -252,4 +252,24 @@ public function testExpiration() $semaphore = new Semaphore($key, $store); $this->assertTrue($semaphore->isExpired()); } + + /** + * @group time-sensitive + */ + public function testExpirationResetAfter() + { + $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + + $key = new Key('key', 1); + $semaphore = new Semaphore($key, $store, 1); + + $semaphore->acquire(); + $this->assertFalse($semaphore->isExpired()); + $semaphore->release(); + + sleep(2); + + $semaphore->acquire(); + $this->assertFalse($semaphore->isExpired()); + } } From d019d3822015ccdc1dd3508c435d87ec12246455 Mon Sep 17 00:00:00 2001 From: Matthew Smeets Date: Thu, 15 Oct 2020 20:55:38 +0200 Subject: [PATCH 014/146] Reference the correct interface in the RegistryInterface deprecation in upgrade notes --- UPGRADE-4.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index bcdee9ca1311f..2e81075a42180 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -64,7 +64,7 @@ DoctrineBridge injected instead. * Deprecated passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field. * Deprecated not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field. - * Deprecated `RegistryInterface`, use `Doctrine\Common\Persistence\ManagerRegistry`. + * Deprecated `RegistryInterface`, use `Doctrine\Persistence\ManagerRegistry`. * Added a new `getMetadataDriverClass` method to replace class parameters in `AbstractDoctrineExtension`. This method will be abstract in Symfony 5 and must be declared in extending classes. From 91fa3e311d029de2bdd3fff276bee2eaccc05563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 15 Oct 2020 21:27:13 +0200 Subject: [PATCH 015/146] Deprecate lock.store aliases --- UPGRADE-5.2.md | 2 +- UPGRADE-6.0.md | 2 +- .../Bundle/FrameworkBundle/CHANGELOG.md | 2 +- .../FrameworkExtension.php | 13 +++-- src/Symfony/Component/Lock/CHANGELOG.md | 1 + src/Symfony/Component/Lock/LockFactory.php | 14 ++++- .../Component/Lock/Tests/LockFactoryTest.php | 55 ++++++++++++++++++- .../Component/Semaphore/SemaphoreFactory.php | 11 +++- .../Semaphore/Tests/SemaphoreFactoryTest.php | 53 +++++++++++++++++- 9 files changed, 136 insertions(+), 17 deletions(-) diff --git a/UPGRADE-5.2.md b/UPGRADE-5.2.md index ff29d10c8cfbe..36859edc762cf 100644 --- a/UPGRADE-5.2.md +++ b/UPGRADE-5.2.md @@ -15,7 +15,7 @@ FrameworkBundle keep cache namespaces separated by environment of the app. The `%kernel.container_class%` (which includes the environment) used to be added by default to the seed, which is not the case anymore. This allows sharing caches between apps or different environments. - * Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. + * Deprecated the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. Form ---- diff --git a/UPGRADE-6.0.md b/UPGRADE-6.0.md index 1bedeaad74a51..2ee58d9ce8f78 100644 --- a/UPGRADE-6.0.md +++ b/UPGRADE-6.0.md @@ -58,7 +58,7 @@ FrameworkBundle * Removed `session.attribute_bag` service and `session.flash_bag` service. * The `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`, `cache_clearer`, `filesystem` and `validator` services are now private. - * Removed the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. + * Removed the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. HttpFoundation -------------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 0d12982902503..dde9bada0961f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -14,7 +14,7 @@ CHANGELOG * added `assertCheckboxChecked()` and `assertCheckboxNotChecked()` in `WebTestCase` * added `assertFormValue()` and `assertNoFormValue()` in `WebTestCase` * Added "--as-tree=3" option to `translation:update` command to dump messages as a tree-like structure. The given value defines the level where to switch to inline YAML - * Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. + * Deprecated the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead. 5.1.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3a7ab77a563bb..c9f9d405cc65e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1674,14 +1674,15 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont if (\count($storeDefinitions) > 1) { $combinedDefinition = new ChildDefinition('lock.store.combined.abstract'); $combinedDefinition->replaceArgument(0, $storeDefinitions); - $container->setDefinition('lock.'.$resourceName.'.store', $combinedDefinition); + $container->setDefinition('lock.'.$resourceName.'.store', $combinedDefinition)->setDeprecated('symfony/framework-bundle', '5.2', 'The "%service_id%" service is deprecated, use "lock.'.$resourceName.'.factory" instead.'); + $container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($resourceStores), $combinedDefinition); } else { - $container->setAlias('lock.'.$resourceName.'.store', new Alias((string) $storeDefinitions[0], false)); + $container->setAlias('lock.'.$resourceName.'.store', (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.'.$resourceName.'.factory" instead.')); } // Generate factories for each resource $factoryDefinition = new ChildDefinition('lock.factory.abstract'); - $factoryDefinition->replaceArgument(0, new Reference('lock.'.$resourceName.'.store')); + $factoryDefinition->replaceArgument(0, new Reference($storeDefinitionId)); $container->setDefinition('lock.'.$resourceName.'.factory', $factoryDefinition); // Generate services for lock instances @@ -1693,14 +1694,14 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont // provide alias for default resource if ('default' === $resourceName) { - $container->setAlias('lock.store', new Alias('lock.'.$resourceName.'.store', false)); + $container->setAlias('lock.store', (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.factory" instead.')); $container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false)); $container->setAlias('lock', (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.factory" instead.')); - $container->setAlias(PersistingStoreInterface::class, new Alias('lock.store', false)); + $container->setAlias(PersistingStoreInterface::class, (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.'" instead.')); $container->setAlias(LockFactory::class, new Alias('lock.factory', false)); $container->setAlias(LockInterface::class, (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.'" instead.')); } else { - $container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistingStoreInterface::class, $resourceName.'.lock.store'); + $container->registerAliasForArgument($storeDefinitionId, PersistingStoreInterface::class, $resourceName.'.lock.store')->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.' '.$resourceName.'LockFactory" instead.'); $container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory'); $container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock')->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.' $'.$resourceName.'LockFactory" instead.'); } diff --git a/src/Symfony/Component/Lock/CHANGELOG.md b/src/Symfony/Component/Lock/CHANGELOG.md index 360c1ebbe914d..4c85f76587973 100644 --- a/src/Symfony/Component/Lock/CHANGELOG.md +++ b/src/Symfony/Component/Lock/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * deprecated `RetryTillSaveStore`, logic has been moved in `Lock` and is not needed anymore. * added `InMemoryStore` * added `PostgreSqlStore` + * added the `LockFactory::CreateLockFromKey()` method. 5.1.0 ----- diff --git a/src/Symfony/Component/Lock/LockFactory.php b/src/Symfony/Component/Lock/LockFactory.php index 82bcd01605f53..11e3bd2ec8fb3 100644 --- a/src/Symfony/Component/Lock/LockFactory.php +++ b/src/Symfony/Component/Lock/LockFactory.php @@ -43,7 +43,19 @@ public function __construct(PersistingStoreInterface $store) */ public function createLock(string $resource, ?float $ttl = 300.0, bool $autoRelease = true): LockInterface { - $lock = new Lock(new Key($resource), $this->store, $ttl, $autoRelease); + return $this->createLockFromKey(new Key($resource), $ttl, $autoRelease); + } + + /** + * Creates a lock from the given key. + * + * @param Key $key The key containing the lock's state + * @param float|null $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + */ + public function createLockFromKey(Key $key, ?float $ttl = 300.0, bool $autoRelease = true): LockInterface + { + $lock = new Lock($key, $this->store, $ttl, $autoRelease); $lock->setLogger($this->logger); return $lock; diff --git a/src/Symfony/Component/Lock/Tests/LockFactoryTest.php b/src/Symfony/Component/Lock/Tests/LockFactoryTest.php index 376bd692a5d00..7026d02b24440 100644 --- a/src/Symfony/Component/Lock/Tests/LockFactoryTest.php +++ b/src/Symfony/Component/Lock/Tests/LockFactoryTest.php @@ -13,8 +13,8 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\Key; use Symfony\Component\Lock\LockFactory; -use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\PersistingStoreInterface; /** @@ -25,12 +25,61 @@ class LockFactoryTest extends TestCase public function testCreateLock() { $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + $store->expects($this->any())->method('exists')->willReturn(false); + + $keys = []; + $store + ->expects($this->exactly(2)) + ->method('save') + ->with($this->callback(function ($key) use (&$keys) { + $keys[] = $key; + + return true; + })) + ->willReturn(true); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $factory = new LockFactory($store); $factory->setLogger($logger); - $lock = $factory->createLock('foo'); + $lock1 = $factory->createLock('foo'); + $lock2 = $factory->createLock('foo'); + + // assert lock1 and lock2 don't share the same state + $lock1->acquire(); + $lock2->acquire(); + + $this->assertNotSame($keys[0], $keys[1]); + } + + public function testCreateLockFromKey() + { + $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + $store->expects($this->any())->method('exists')->willReturn(false); + + $keys = []; + $store + ->expects($this->exactly(2)) + ->method('save') + ->with($this->callback(function ($key) use (&$keys) { + $keys[] = $key; + + return true; + })) + ->willReturn(true); + + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $factory = new LockFactory($store); + $factory->setLogger($logger); + + $key = new Key('foo'); + $lock1 = $factory->createLockFromKey($key); + $lock2 = $factory->createLockFromKey($key); + + // assert lock1 and lock2 share the same state + $lock1->acquire(); + $lock2->acquire(); - $this->assertInstanceOf(LockInterface::class, $lock); + $this->assertSame($keys[0], $keys[1]); } } diff --git a/src/Symfony/Component/Semaphore/SemaphoreFactory.php b/src/Symfony/Component/Semaphore/SemaphoreFactory.php index bf4743e8f767b..9194817f096e3 100644 --- a/src/Symfony/Component/Semaphore/SemaphoreFactory.php +++ b/src/Symfony/Component/Semaphore/SemaphoreFactory.php @@ -42,7 +42,16 @@ public function __construct(PersistingStoreInterface $store) */ public function createSemaphore(string $resource, int $limit, int $weight = 1, ?float $ttlInSecond = 300.0, bool $autoRelease = true): SemaphoreInterface { - $semaphore = new Semaphore(new Key($resource, $limit, $weight), $this->store, $ttlInSecond, $autoRelease); + return $this->createSemaphoreFromKey(new Key($resource, $limit, $weight), $ttlInSecond, $autoRelease); + } + + /** + * @param float|null $ttlInSecond Maximum expected semaphore duration in seconds + * @param bool $autoRelease Whether to automatically release the semaphore or not when the semaphore instance is destroyed + */ + public function createSemaphoreFromKey(Key $key, ?float $ttlInSecond = 300.0, bool $autoRelease = true): SemaphoreInterface + { + $semaphore = new Semaphore($key, $this->store, $ttlInSecond, $autoRelease); $semaphore->setLogger($this->logger); return $semaphore; diff --git a/src/Symfony/Component/Semaphore/Tests/SemaphoreFactoryTest.php b/src/Symfony/Component/Semaphore/Tests/SemaphoreFactoryTest.php index cf79154632691..5156f64671d03 100644 --- a/src/Symfony/Component/Semaphore/Tests/SemaphoreFactoryTest.php +++ b/src/Symfony/Component/Semaphore/Tests/SemaphoreFactoryTest.php @@ -13,9 +13,9 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; +use Symfony\Component\Semaphore\Key; use Symfony\Component\Semaphore\PersistingStoreInterface; use Symfony\Component\Semaphore\SemaphoreFactory; -use Symfony\Component\Semaphore\SemaphoreInterface; /** * @author Jérémy Derussé @@ -26,12 +26,59 @@ class SemaphoreFactoryTest extends TestCase public function testCreateSemaphore() { $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + + $keys = []; + $store + ->expects($this->exactly(2)) + ->method('save') + ->with($this->callback(function ($key) use (&$keys) { + $keys[] = $key; + + return true; + })) + ->willReturn(true); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $factory = new SemaphoreFactory($store); $factory->setLogger($logger); - $semaphore = $factory->createSemaphore('foo', 4); + $semaphore1 = $factory->createSemaphore('foo', 4); + $semaphore2 = $factory->createSemaphore('foo', 4); + + // assert lock1 and lock2 don't share the same state + $semaphore1->acquire(); + $semaphore2->acquire(); + + $this->assertNotSame($keys[0], $keys[1]); + } + + public function testCreateSemaphoreFromKey() + { + $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + + $keys = []; + $store + ->expects($this->exactly(2)) + ->method('save') + ->with($this->callback(function ($key) use (&$keys) { + $keys[] = $key; + + return true; + })) + ->willReturn(true); + + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $factory = new SemaphoreFactory($store); + $factory->setLogger($logger); + + $key = new Key('foo', 4); + $semaphore1 = $factory->createSemaphoreFromKey($key); + $semaphore2 = $factory->createSemaphoreFromKey($key); + + // assert lock1 and lock2 share the same state + $semaphore1->acquire(); + $semaphore2->acquire(); - $this->assertInstanceOf(SemaphoreInterface::class, $semaphore); + $this->assertSame($keys[0], $keys[1]); } } From 8fe876341e860ea3fa13bec3c2bdf77a66ead424 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 15 Oct 2020 14:55:10 +0200 Subject: [PATCH 016/146] [Console] Don't register signal handlers if pcntl is disabled --- src/Symfony/Component/Console/Application.php | 8 ++++++-- .../Console/SignalRegistry/SignalRegistry.php | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 79217013ee5bb..0e98d9bdd53cd 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -24,6 +24,7 @@ use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\NamespaceNotFoundException; +use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\DebugFormatterHelper; use Symfony\Component\Console\Helper\FormatterHelper; @@ -88,8 +89,8 @@ public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN $this->version = $version; $this->terminal = new Terminal(); $this->defaultCommand = 'list'; - $this->signalRegistry = new SignalRegistry(); - if (\defined('SIGINT')) { + if (\defined('SIGINT') && SignalRegistry::isSupported()) { + $this->signalRegistry = new SignalRegistry(); $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; } } @@ -953,6 +954,9 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } if ($command instanceof SignalableCommandInterface) { + if (!$this->signalsToDispatchEvent) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } foreach ($command->getSubscribedSignals() as $signal) { $this->signalRegistry->register($signal, [$command, 'handleSignal']); } diff --git a/src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php b/src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php index de256376d7cb1..ed93dd062fdae 100644 --- a/src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php +++ b/src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php @@ -37,6 +37,19 @@ public function register(int $signal, callable $signalHandler): void pcntl_signal($signal, [$this, 'handle']); } + public static function isSupported(): bool + { + if (!\function_exists('pcntl_signal')) { + return false; + } + + if (\in_array('pcntl_signal', explode(',', ini_get('disable_functions')))) { + return false; + } + + return true; + } + /** * @internal */ From 5e1ac09de930ae5129c47be83506332f951c4ac1 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 14 Oct 2020 19:12:27 -0400 Subject: [PATCH 017/146] Add myself to CODEOWNERS for Form, OptionsResolver and TwigBundle --- .github/CODEOWNERS | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 37b2dbfcdc0e6..0870dcfdd5cc4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,8 +3,8 @@ /src/Symfony/Component/Console/Logger/ConsoleLogger.php @dunglas # DependencyInjection /src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @dunglas -# ErrorRenderer -/src/Symfony/Component/ErrorRenderer/* @yceruto +# ErrorHandler +/src/Symfony/Component/ErrorHandler/ @yceruto # Form /src/Symfony/Bridge/Twig/Extension/FormExtension.php @xabbuh /src/Symfony/Bridge/Twig/Form/ @xabbuh @@ -21,7 +21,7 @@ /src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php @xabbuh /src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @xabbuh /src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @xabbuh -/src/Symfony/Component/Form/ @xabbuh +/src/Symfony/Component/Form/ @xabbuh @yceruto # HttpKernel /src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas # LDAP @@ -31,6 +31,8 @@ # Messenger /src/Symfony/Bridge/Doctrine/Messenger/ @sroze /src/Symfony/Component/Messenger/ @sroze +# OptionsResolver +/src/Symfony/Component/OptionsResolver/ @yceruto # PropertyInfo /src/Symfony/Component/PropertyInfo/ @dunglas /src/Symfony/Bridge/Doctrine/PropertyInfo/ @dunglas @@ -42,7 +44,7 @@ /src/Symfony/Component/Security/ @wouterj @chalasr /src/Symfony/Component/Ldap/Security/ @wouterj @chalasr # TwigBundle -/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @yceruto +/src/Symfony/Bundle/TwigBundle/ @yceruto # WebLink /src/Symfony/Component/WebLink/ @dunglas # Workflow From cd34f2125423b6792c175528d90652ff29f525cf Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 11 Oct 2020 16:16:32 +0200 Subject: [PATCH 018/146] [RateLimiter] Added reserve() to LimiterInterface and rename Limiter to RateLimiter --- .../FrameworkExtension.php | 4 +- .../Resources/config/rate_limiter.php | 4 +- .../Factory/LoginThrottlingFactory.php | 4 +- .../Component/RateLimiter/CompoundLimiter.php | 7 +++ .../MaxWaitDurationExceededException.php | 15 +++++ .../ReserveNotSupportedException.php | 25 ++++++++ .../RateLimiter/FixedWindowLimiter.php | 60 +++++++++++++------ .../RateLimiter/LimiterInterface.php | 19 ++++++ .../Component/RateLimiter/NoLimiter.php | 5 ++ src/Symfony/Component/RateLimiter/README.md | 4 +- .../{Limiter.php => RateLimiter.php} | 2 +- .../Component/RateLimiter/Reservation.php | 9 ++- .../RateLimiter/SlidingWindowLimiter.php | 6 ++ .../RateLimiter/Tests/CompoundLimiterTest.php | 17 ++++-- .../Tests/FixedWindowLimiterTest.php | 2 +- .../RateLimiter/Tests/LimiterTest.php | 4 +- .../Tests/SlidingWindowLimiterTest.php | 8 +++ .../Tests/Storage/CacheStorageTest.php | 7 +-- .../Component/RateLimiter/TokenBucket.php | 5 ++ .../RateLimiter/TokenBucketLimiter.php | 20 +++---- src/Symfony/Component/RateLimiter/Window.php | 46 ++++++++++++-- .../RateLimiter/DefaultLoginRateLimiter.php | 4 +- .../LoginThrottlingListenerTest.php | 6 +- 23 files changed, 219 insertions(+), 64 deletions(-) create mode 100644 src/Symfony/Component/RateLimiter/Exception/ReserveNotSupportedException.php rename src/Symfony/Component/RateLimiter/{Limiter.php => RateLimiter.php} (99%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 2c92a1a748b2d..d4d377be32ddc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -128,8 +128,8 @@ use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface; -use Symfony\Component\RateLimiter\Limiter; use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\RateLimiter; use Symfony\Component\RateLimiter\Storage\CacheStorage; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; use Symfony\Component\Routing\Loader\AnnotationFileLoader; @@ -2266,7 +2266,7 @@ public static function registerRateLimiter(ContainerBuilder $container, string $ $limiterConfig['id'] = $name; $limiter->replaceArgument(0, $limiterConfig); - $container->registerAliasForArgument($limiterId, Limiter::class, $name.'.limiter'); + $container->registerAliasForArgument($limiterId, RateLimiter::class, $name.'.limiter'); } private function resolveTrustedHeaders(array $headers): int diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php index 104b8023790bd..e9677ae962140 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php @@ -11,7 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; return static function (ContainerConfigurator $container) { $container->services() @@ -19,7 +19,7 @@ ->parent('cache.app') ->tag('cache.pool') - ->set('limiter', Limiter::class) + ->set('limiter', RateLimiter::class) ->abstract() ->args([ abstract_arg('config'), diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index df30cd05786fc..5e08a445c9e15 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -18,7 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; use Symfony\Component\Security\Http\EventListener\LoginThrottlingListener; use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter; @@ -63,7 +63,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal throw new \LogicException('Login throttling requires symfony/security-http:^5.2.'); } - if (!class_exists(Limiter::class)) { + if (!class_exists(RateLimiter::class)) { throw new \LogicException('Login throttling requires symfony/rate-limiter to be installed and enabled.'); } diff --git a/src/Symfony/Component/RateLimiter/CompoundLimiter.php b/src/Symfony/Component/RateLimiter/CompoundLimiter.php index e2a287685bcc3..6722e0b436e70 100644 --- a/src/Symfony/Component/RateLimiter/CompoundLimiter.php +++ b/src/Symfony/Component/RateLimiter/CompoundLimiter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\RateLimiter; +use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; + /** * @author Wouter de Jong * @@ -31,6 +33,11 @@ public function __construct(array $limiters) $this->limiters = $limiters; } + public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation + { + throw new ReserveNotSupportedException(__CLASS__); + } + public function consume(int $tokens = 1): Limit { $minimalLimit = null; diff --git a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php index 4e4e7fcaac9d7..025103f7a8741 100644 --- a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php +++ b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php @@ -11,6 +11,8 @@ namespace Symfony\Component\RateLimiter\Exception; +use Symfony\Component\RateLimiter\Limit; + /** * @author Wouter de Jong * @@ -18,4 +20,17 @@ */ class MaxWaitDurationExceededException extends \RuntimeException { + private $limit; + + public function __construct(string $message, Limit $limit, int $code = 0, ?\Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + + $this->limit = $limit; + } + + public function getLimit(): Limit + { + return $this->limit; + } } diff --git a/src/Symfony/Component/RateLimiter/Exception/ReserveNotSupportedException.php b/src/Symfony/Component/RateLimiter/Exception/ReserveNotSupportedException.php new file mode 100644 index 0000000000000..852c99ae1d698 --- /dev/null +++ b/src/Symfony/Component/RateLimiter/Exception/ReserveNotSupportedException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter\Exception; + +/** + * @author Wouter de Jong + * + * @experimental in 5.2 + */ +class ReserveNotSupportedException extends \BadMethodCallException +{ + public function __construct(string $limiterClass, int $code = 0, ?\Throwable $previous = null) + { + parent::__construct(sprintf('Reserving tokens is not supported by "%s".', $limiterClass), $code, $previous); + } +} diff --git a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php index 1e5c2a46f3b31..9164eb4ae55ee 100644 --- a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php @@ -13,6 +13,7 @@ use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\NoLock; +use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\Util\TimeUtil; @@ -33,6 +34,10 @@ final class FixedWindowLimiter implements LimiterInterface public function __construct(string $id, int $limit, \DateInterval $interval, StorageInterface $storage, ?LockInterface $lock = null) { + if ($limit < 1) { + throw new \InvalidArgumentException(sprintf('Cannot set the limit of "%s" to 0, as that would never accept any hit.', __CLASS__)); + } + $this->storage = $storage; $this->lock = $lock ?? new NoLock(); $this->id = $id; @@ -40,42 +45,61 @@ public function __construct(string $id, int $limit, \DateInterval $interval, Sto $this->interval = TimeUtil::dateIntervalToSeconds($interval); } - /** - * {@inheritdoc} - */ - public function consume(int $tokens = 1): Limit + public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation { + if ($tokens > $this->limit) { + throw new \InvalidArgumentException(sprintf('Cannot reserve more tokens (%d) than the size of the rate limiter (%d).', $tokens, $this->limit)); + } + $this->lock->acquire(true); try { $window = $this->storage->fetch($this->id); if (!$window instanceof Window) { - $window = new Window($this->id, $this->interval); + $window = new Window($this->id, $this->interval, $this->limit); } - $hitCount = $window->getHitCount(); - $availableTokens = $this->getAvailableTokens($hitCount); - $windowStart = \DateTimeImmutable::createFromFormat('U', time()); - if ($availableTokens < $tokens) { - return new Limit($availableTokens, $this->getRetryAfter($windowStart), false); - } + $now = microtime(true); + $availableTokens = $window->getAvailableTokens($now); + if ($availableTokens >= $tokens) { + $window->add($tokens); - $window->add($tokens); - $this->storage->save($window); + $reservation = new Reservation($now, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); + } else { + $remainingTokens = $tokens - $availableTokens; + $waitDuration = $window->calculateTimeForTokens($remainingTokens); - return new Limit($this->getAvailableTokens($window->getHitCount()), $this->getRetryAfter($windowStart), true); + if (null !== $maxTime && $waitDuration > $maxTime) { + // process needs to wait longer than set interval + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + } + + $window->add($tokens); + + $reservation = new Reservation($now + $waitDuration, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + } + $this->storage->save($window); } finally { $this->lock->release(); } + + return $reservation; } - public function getAvailableTokens(int $hitCount): int + /** + * {@inheritdoc} + */ + public function consume(int $tokens = 1): Limit { - return $this->limit - $hitCount; + try { + return $this->reserve($tokens, 0)->getLimit(); + } catch (MaxWaitDurationExceededException $e) { + return $e->getLimit(); + } } - private function getRetryAfter(\DateTimeImmutable $windowStart): \DateTimeImmutable + public function getAvailableTokens(int $hitCount): int { - return $windowStart->add(new \DateInterval(sprintf('PT%sS', $this->interval))); + return $this->limit - $hitCount; } } diff --git a/src/Symfony/Component/RateLimiter/LimiterInterface.php b/src/Symfony/Component/RateLimiter/LimiterInterface.php index d768081594e96..e04a7ea26b4f0 100644 --- a/src/Symfony/Component/RateLimiter/LimiterInterface.php +++ b/src/Symfony/Component/RateLimiter/LimiterInterface.php @@ -11,6 +11,9 @@ namespace Symfony\Component\RateLimiter; +use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException; +use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; + /** * @author Wouter de Jong * @@ -18,6 +21,22 @@ */ interface LimiterInterface { + /** + * Waits until the required number of tokens is available. + * + * The reserved tokens will be taken into account when calculating + * future token consumptions. Do not use this method if you intend + * to skip this process. + * + * @param int $tokens the number of tokens required + * @param float $maxTime maximum accepted waiting time in seconds + * + * @throws MaxWaitDurationExceededException if $maxTime is set and the process needs to wait longer than its value (in seconds) + * @throws ReserveNotSupportedException if this limiter implementation doesn't support reserving tokens + * @throws \InvalidArgumentException if $tokens is larger than the maximum burst size + */ + public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation; + /** * Use this method if you intend to drop if the required number * of tokens is unavailable. diff --git a/src/Symfony/Component/RateLimiter/NoLimiter.php b/src/Symfony/Component/RateLimiter/NoLimiter.php index b5f5d5f68c4c6..65f772a66efe1 100644 --- a/src/Symfony/Component/RateLimiter/NoLimiter.php +++ b/src/Symfony/Component/RateLimiter/NoLimiter.php @@ -23,6 +23,11 @@ */ final class NoLimiter implements LimiterInterface { + public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation + { + return new Reservation(time(), new Limit(\INF, new \DateTimeImmutable(), true)); + } + public function consume(int $tokens = 1): Limit { return new Limit(\INF, new \DateTimeImmutable(), true); diff --git a/src/Symfony/Component/RateLimiter/README.md b/src/Symfony/Component/RateLimiter/README.md index 0d4ff465e3980..18e91b9e09f47 100644 --- a/src/Symfony/Component/RateLimiter/README.md +++ b/src/Symfony/Component/RateLimiter/README.md @@ -18,9 +18,9 @@ $ composer require symfony/rate-limiter ```php use Symfony\Component\RateLimiter\Storage\InMemoryStorage; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; -$limiter = new Limiter([ +$limiter = new RateLimiter([ 'id' => 'login', 'strategy' => 'token_bucket', // or 'fixed_window' 'limit' => 10, diff --git a/src/Symfony/Component/RateLimiter/Limiter.php b/src/Symfony/Component/RateLimiter/RateLimiter.php similarity index 99% rename from src/Symfony/Component/RateLimiter/Limiter.php rename to src/Symfony/Component/RateLimiter/RateLimiter.php index 61018ab807372..45edecd877942 100644 --- a/src/Symfony/Component/RateLimiter/Limiter.php +++ b/src/Symfony/Component/RateLimiter/RateLimiter.php @@ -22,7 +22,7 @@ * * @experimental in 5.2 */ -final class Limiter +final class RateLimiter { private $config; private $storage; diff --git a/src/Symfony/Component/RateLimiter/Reservation.php b/src/Symfony/Component/RateLimiter/Reservation.php index fc33c5ad0f6ea..26a1d1750d44d 100644 --- a/src/Symfony/Component/RateLimiter/Reservation.php +++ b/src/Symfony/Component/RateLimiter/Reservation.php @@ -19,13 +19,15 @@ final class Reservation { private $timeToAct; + private $limit; /** * @param float $timeToAct Unix timestamp in seconds when this reservation should act */ - public function __construct(float $timeToAct) + public function __construct(float $timeToAct, Limit $limit) { $this->timeToAct = $timeToAct; + $this->limit = $limit; } public function getTimeToAct(): float @@ -38,6 +40,11 @@ public function getWaitDuration(): float return max(0, (-microtime(true)) + $this->timeToAct); } + public function getLimit(): Limit + { + return $this->limit; + } + public function wait(): void { usleep($this->getWaitDuration() * 1e6); diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php index fbc6a41958d5a..dcdf6198439d2 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php @@ -13,6 +13,7 @@ use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\NoLock; +use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\Util\TimeUtil; @@ -67,6 +68,11 @@ public function __construct(string $id, int $limit, \DateInterval $interval, Sto $this->interval = TimeUtil::dateIntervalToSeconds($interval); } + public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation + { + throw new ReserveNotSupportedException(__CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php index aab06fff3913b..fb28996f2069a 100644 --- a/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Component\RateLimiter\CompoundLimiter; +use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; use Symfony\Component\RateLimiter\FixedWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; @@ -38,22 +39,26 @@ public function testConsume() $limiter3 = $this->createLimiter(12, new \DateInterval('PT30S')); $limiter = new CompoundLimiter([$limiter1, $limiter2, $limiter3]); - // Reach limiter 1 limit, verify that limiter2 available tokens reduced by 5 and fetch successfully limiter 1 - $this->assertEquals(3, $limiter->consume(5)->getRemainingTokens(), 'Limiter 1 reached the limit'); + $this->assertEquals(0, $limiter->consume(4)->getRemainingTokens(), 'Limiter 1 reached the limit'); sleep(1); // reset limiter1's window - $this->assertTrue($limiter->consume(2)->isAccepted()); + $this->assertTrue($limiter->consume(3)->isAccepted()); - // Reach limiter 2 limit, verify that limiter2 available tokens reduced by 5 and and fetch successfully $this->assertEquals(0, $limiter->consume()->getRemainingTokens(), 'Limiter 2 has no remaining tokens left'); - sleep(9); // reset limiter2's window + sleep(10); // reset limiter2's window $this->assertTrue($limiter->consume(3)->isAccepted()); - // Reach limiter 3 limit, verify that limiter2 available tokens reduced by 5 and fetch successfully $this->assertEquals(0, $limiter->consume()->getRemainingTokens(), 'Limiter 3 reached the limit'); sleep(20); // reset limiter3's window $this->assertTrue($limiter->consume()->isAccepted()); } + public function testReserve() + { + $this->expectException(ReserveNotSupportedException::class); + + (new CompoundLimiter([$this->createLimiter(4, new \DateInterval('PT1S'))]))->reserve(); + } + private function createLimiter(int $limit, \DateInterval $interval): FixedWindowLimiter { return new FixedWindowLimiter('test'.$limit, $limit, $interval, $this->storage); diff --git a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php index 819e748fd5669..a6f436616f933 100644 --- a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php @@ -60,7 +60,7 @@ public function testConsumeOutsideInterval() sleep(10); $limit = $limiter->consume(10); $this->assertEquals(0, $limit->getRemainingTokens()); - $this->assertEquals(time() + 60, $limit->getRetryAfter()->getTimestamp()); + $this->assertTrue($limit->isAccepted()); } public function testWrongWindowFromCache() diff --git a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php index 8d1442f2807ac..c464e1a7e27c3 100644 --- a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Lock\LockFactory; use Symfony\Component\RateLimiter\FixedWindowLimiter; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\TokenBucketLimiter; @@ -61,6 +61,6 @@ public function testWrongInterval() private function createFactory(array $options) { - return new Limiter($options, $this->createMock(StorageInterface::class), $this->createMock(LockFactory::class)); + return new RateLimiter($options, $this->createMock(StorageInterface::class), $this->createMock(LockFactory::class)); } } diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php index 589d4e5550719..341f216c29df4 100644 --- a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ClockMock; +use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; use Symfony\Component\RateLimiter\SlidingWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; @@ -50,6 +51,13 @@ public function testConsume() $this->assertTrue($limit->isAccepted()); } + public function testReserve() + { + $this->expectException(ReserveNotSupportedException::class); + + $this->createLimiter()->reserve(); + } + private function createLimiter(): SlidingWindowLimiter { return new SlidingWindowLimiter('test', 10, new \DateInterval('PT12S'), $this->storage); diff --git a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php index a7baae6c882ea..de8f77b4630e8 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php @@ -31,15 +31,14 @@ protected function setUp(): void public function testSave() { $cacheItem = $this->createMock(CacheItemInterface::class); - $cacheItem->expects($this->once())->method('expiresAfter')->with(10); + $cacheItem->expects($this->exactly(2))->method('expiresAfter')->with(10); $this->pool->expects($this->any())->method('getItem')->with(sha1('test'))->willReturn($cacheItem); $this->pool->expects($this->exactly(2))->method('save')->with($cacheItem); - $window = new Window('test', 10); + $window = new Window('test', 10, 20); $this->storage->save($window); - // test that expiresAfter is only called when getExpirationAt() does not return null $window = unserialize(serialize($window)); $this->storage->save($window); } @@ -47,7 +46,7 @@ public function testSave() public function testFetchExistingState() { $cacheItem = $this->createMock(CacheItemInterface::class); - $window = new Window('test', 10); + $window = new Window('test', 10, 20); $cacheItem->expects($this->any())->method('get')->willReturn($window); $cacheItem->expects($this->any())->method('isHit')->willReturn(true); diff --git a/src/Symfony/Component/RateLimiter/TokenBucket.php b/src/Symfony/Component/RateLimiter/TokenBucket.php index 01de558f35373..c7fbcb5ebc453 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/TokenBucket.php @@ -14,6 +14,7 @@ /** * @author Wouter de Jong * + * @internal * @experimental in 5.2 */ final class TokenBucket implements LimiterStateInterface @@ -32,6 +33,10 @@ final class TokenBucket implements LimiterStateInterface */ public function __construct(string $id, int $initialTokens, Rate $rate, ?float $timer = null) { + if ($initialTokens < 1) { + throw new \InvalidArgumentException(sprintf('Cannot set the limit of "%s" to 0, as that would never accept any hit.', TokenBucketLimiter::class)); + } + $this->id = $id; $this->tokens = $this->burstSize = $initialTokens; $this->rate = $rate; diff --git a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php index 05e5bb893bbf1..b8997ac7e04a8 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php @@ -74,14 +74,16 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation $bucket->setTokens($availableTokens - $tokens); $bucket->setTimer($now); - $reservation = new Reservation($now); + $reservation = new Reservation($now, new Limit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); } else { $remainingTokens = $tokens - $availableTokens; $waitDuration = $this->rate->calculateTimeForTokens($remainingTokens); if (null !== $maxTime && $waitDuration > $maxTime) { // process needs to wait longer than set interval - throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime)); + $limit = new Limit($availableTokens, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false); + + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), $limit); } // at $now + $waitDuration all tokens will be reserved for this process, @@ -89,7 +91,7 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation $bucket->setTokens(0); $bucket->setTimer($now + $waitDuration); - $reservation = new Reservation($bucket->getTimer()); + $reservation = new Reservation($bucket->getTimer(), new Limit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); } $this->storage->save($bucket); @@ -105,18 +107,10 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation */ public function consume(int $tokens = 1): Limit { - $bucket = $this->storage->fetch($this->id); - if (!$bucket instanceof TokenBucket) { - $bucket = new TokenBucket($this->id, $this->maxBurst, $this->rate); - } - $now = microtime(true); - try { - $this->reserve($tokens, 0); - - return new Limit($bucket->getAvailableTokens($now) - $tokens, $this->rate->calculateNextTokenAvailability(), true); + return $this->reserve($tokens, 0)->getLimit(); } catch (MaxWaitDurationExceededException $e) { - return new Limit($bucket->getAvailableTokens($now), $this->rate->calculateNextTokenAvailability(), false); + return $e->getLimit(); } } } diff --git a/src/Symfony/Component/RateLimiter/Window.php b/src/Symfony/Component/RateLimiter/Window.php index e7966aa5fec79..46ca1b38204b6 100644 --- a/src/Symfony/Component/RateLimiter/Window.php +++ b/src/Symfony/Component/RateLimiter/Window.php @@ -14,6 +14,7 @@ /** * @author Wouter de Jong * + * @internal * @experimental in 5.2 */ final class Window implements LimiterStateInterface @@ -21,11 +22,15 @@ final class Window implements LimiterStateInterface private $id; private $hitCount = 0; private $intervalInSeconds; + private $maxSize; + private $timer; - public function __construct(string $id, int $intervalInSeconds) + public function __construct(string $id, int $intervalInSeconds, int $windowSize, ?float $timer = null) { $this->id = $id; $this->intervalInSeconds = $intervalInSeconds; + $this->maxSize = $windowSize; + $this->timer = $timer ?? microtime(true); } public function getId(): string @@ -38,8 +43,15 @@ public function getExpirationTime(): ?int return $this->intervalInSeconds; } - public function add(int $hits = 1) + public function add(int $hits = 1, ?float $now = null) { + $now = $now ?? microtime(true); + if (($now - $this->timer) > $this->intervalInSeconds) { + // reset window + $this->timer = $now; + $this->hitCount = 0; + } + $this->hitCount += $hits; } @@ -48,13 +60,37 @@ public function getHitCount(): int return $this->hitCount; } + public function getAvailableTokens(float $now) + { + // if timer is in future, there are no tokens available anymore + if ($this->timer > $now) { + return 0; + } + + // if now is more than the window interval in the past, all tokens are available + if (($now - $this->timer) > $this->intervalInSeconds) { + return $this->maxSize; + } + + return $this->maxSize - $this->hitCount; + } + + public function calculateTimeForTokens(int $tokens): int + { + if (($this->maxSize - $this->hitCount) >= $tokens) { + return 0; + } + + $cyclesRequired = ceil($tokens / $this->maxSize); + + return $cyclesRequired * $this->intervalInSeconds; + } + /** * @internal */ public function __sleep(): array { - // $intervalInSeconds is not serialized, it should only be set - // upon first creation of the Window. - return ['id', 'hitCount']; + return ['id', 'hitCount', 'intervalInSeconds', 'timer', 'maxSize']; } } diff --git a/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php b/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php index bf7735bc369b9..f5b69674e78c6 100644 --- a/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php +++ b/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpFoundation\RateLimiter\AbstractRequestRateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; use Symfony\Component\Security\Core\Security; /** @@ -31,7 +31,7 @@ final class DefaultLoginRateLimiter extends AbstractRequestRateLimiter private $globalLimiter; private $localLimiter; - public function __construct(Limiter $globalLimiter, Limiter $localLimiter) + public function __construct(RateLimiter $globalLimiter, RateLimiter $localLimiter) { $this->globalLimiter = $globalLimiter; $this->localLimiter = $localLimiter; diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php index 28af3713fca18..4425afa8b058d 100644 --- a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\RateLimiter\Limiter; +use Symfony\Component\RateLimiter\RateLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\TooManyLoginAttemptsAuthenticationException; @@ -35,13 +35,13 @@ protected function setUp(): void { $this->requestStack = new RequestStack(); - $localLimiter = new Limiter([ + $localLimiter = new RateLimiter([ 'id' => 'login', 'strategy' => 'fixed_window', 'limit' => 3, 'interval' => '1 minute', ], new InMemoryStorage()); - $globalLimiter = new Limiter([ + $globalLimiter = new RateLimiter([ 'id' => 'login', 'strategy' => 'fixed_window', 'limit' => 6, From 2ee24a0592633188b22e160660c51fa3737ae27b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 16 Oct 2020 10:33:02 +0200 Subject: [PATCH 019/146] do not translate null placeholders or titles --- .../Bridge/Twig/Resources/views/Form/form_div_layout.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index cee716eb47b33..362e27ce954ed 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -399,7 +399,7 @@ {%- for attrname, attrvalue in attr -%} {{- " " -}} {%- if attrname in ['placeholder', 'title'] -%} - {{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}" + {{- attrname }}="{{ translation_domain is same as(false) or attrvalue is null ? attrvalue : attrvalue|trans({}, translation_domain) }}" {%- elseif attrvalue is same as(true) -%} {{- attrname }}="{{ attrname }}" {%- elseif attrvalue is not same as(false) -%} From 36e41b85d8890a0e8a7cc4c07b41bc06b1055bf7 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 16 Oct 2020 14:31:14 +0200 Subject: [PATCH 020/146] [Console] Fix Application::getSignalRegistry() retval --- src/Symfony/Component/Console/Application.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 0e98d9bdd53cd..0efccdb103002 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -110,6 +110,10 @@ public function setCommandLoader(CommandLoaderInterface $commandLoader) public function getSignalRegistry(): SignalRegistry { + if (!$this->signalRegistry) { + throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + return $this->signalRegistry; } @@ -282,7 +286,7 @@ public function doRun(InputInterface $input, OutputInterface $output) $command = $this->find($alternative); } - if ($this->dispatcher) { + if ($this->dispatcher && $this->signalRegistry) { foreach ($this->signalsToDispatchEvent as $signal) { $event = new ConsoleSignalEvent($command, $input, $output, $signal); @@ -954,7 +958,7 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } if ($command instanceof SignalableCommandInterface) { - if (!$this->signalsToDispatchEvent) { + if (!$this->signalRegistry) { throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } foreach ($command->getSubscribedSignals() as $signal) { From fd3a6e8a0a1c13778f24527af20442d69d848c43 Mon Sep 17 00:00:00 2001 From: Kai Date: Fri, 16 Oct 2020 13:40:40 +0200 Subject: [PATCH 021/146] [DoctrineBridge] Convert values to Rfc4122 before inserting them into the database --- .../Bridge/Doctrine/Tests/Types/UlidTypeTest.php | 9 ++++++--- .../Bridge/Doctrine/Tests/Types/UuidTypeTest.php | 2 +- src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php | 10 ++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php index 638b178b3783e..328df993b2690 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php @@ -48,7 +48,7 @@ public function testUlidConvertsToDatabaseValue(): void { $ulid = Ulid::fromString(self::DUMMY_ULID); - $expected = $ulid->__toString(); + $expected = $ulid->toRfc4122(); $actual = $this->type->convertToDatabaseValue($ulid, $this->platform); $this->assertEquals($expected, $actual); @@ -60,7 +60,7 @@ public function testUlidInterfaceConvertsToDatabaseValue(): void $ulid ->expects($this->once()) - ->method('__toString') + ->method('toRfc4122') ->willReturn('foo'); $actual = $this->type->convertToDatabaseValue($ulid, $this->platform); @@ -71,8 +71,11 @@ public function testUlidInterfaceConvertsToDatabaseValue(): void public function testUlidStringConvertsToDatabaseValue(): void { $actual = $this->type->convertToDatabaseValue(self::DUMMY_ULID, $this->platform); + $ulid = Ulid::fromString(self::DUMMY_ULID); + + $expected = $ulid->toRfc4122(); - $this->assertEquals(self::DUMMY_ULID, $actual); + $this->assertEquals($expected, $actual); } public function testInvalidUlidConversionForDatabaseValue(): void diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php index 4ce96fae32fac..a61526cc3dc10 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php @@ -60,7 +60,7 @@ public function testUuidInterfaceConvertsToDatabaseValue(): void $uuid ->expects($this->once()) - ->method('__toString') + ->method('toRfc4122') ->willReturn('foo'); $actual = $this->type->convertToDatabaseValue($uuid, $this->platform); diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php index b64ad584b8228..2286bb7268191 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php @@ -56,7 +56,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str } if ($value instanceof AbstractUid) { - return (string) $value; + return $value->toRfc4122(); } if (!\is_string($value) && !(\is_object($value) && method_exists($value, '__toString'))) { @@ -64,7 +64,13 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str } if ($this->getUidClass()::isValid((string) $value)) { - return (string) $value; + try { + $uuid = $this->getUidClass()::fromString($value); + + return $uuid->toRfc4122(); + } catch (\InvalidArgumentException $e) { + throw ConversionException::conversionFailed($value, $this->getName()); + } } throw ConversionException::conversionFailed($value, $this->getName()); From af1a6208ec3f2dae1319dea1ac7047aa328d3c2a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 16 Oct 2020 16:03:05 +0200 Subject: [PATCH 022/146] indexBy does not refer to attributes, but to column names --- .../Doctrine/PropertyInfo/DoctrineExtractor.php | 13 ++----------- .../Tests/PropertyInfo/Fixtures/DoctrineDummy.php | 2 +- .../PropertyInfo/Fixtures/DoctrineRelation.php | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index bafd97a50c963..0cfdc8768c9fe 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -110,19 +110,10 @@ public function getTypes($class, $property, array $context = []) $associationMapping = $metadata->getAssociationMapping($property); if (isset($associationMapping['indexBy'])) { - $indexProperty = $associationMapping['indexBy']; + $indexColumn = $associationMapping['indexBy']; /** @var ClassMetadataInfo $subMetadata */ $subMetadata = $this->classMetadataFactory->getMetadataFor($associationMapping['targetEntity']); - $typeOfField = $subMetadata->getTypeOfField($indexProperty); - - if (null === $typeOfField) { - $associationMapping = $subMetadata->getAssociationMapping($indexProperty); - - /** @var ClassMetadataInfo $subMetadata */ - $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($indexProperty); - $subMetadata = $this->classMetadataFactory->getMetadataFor($associationMapping['targetEntity']); - $typeOfField = $subMetadata->getTypeOfField($indexProperty); - } + $typeOfField = $subMetadata->getTypeOfField($subMetadata->getFieldForColumn($indexColumn)); if (!$collectionKeyType = $this->getPhpType($typeOfField)) { return null; diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php index 81264fad27c5f..568efce33d382 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php @@ -42,7 +42,7 @@ class DoctrineDummy public $bar; /** - * @ManyToMany(targetEntity="DoctrineRelation", indexBy="rguid") + * @ManyToMany(targetEntity="DoctrineRelation", indexBy="rguid_column") */ protected $indexedBar; diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php index 5730cf81dd493..e480ca9d777ba 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php @@ -30,7 +30,7 @@ class DoctrineRelation public $id; /** - * @Column(type="guid") + * @Column(type="guid", name="rguid_column") */ protected $rguid; From fb305160cacc1e778b41c99e092d42d47925d253 Mon Sep 17 00:00:00 2001 From: Jason Tan Date: Fri, 16 Oct 2020 10:46:58 -0500 Subject: [PATCH 023/146] [WebProfilerBundle] Hide debug toolbar in print view --- .../WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 4012625e85d15..cf406339fe942 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -565,6 +565,6 @@ div.sf-toolbar .sf-toolbar-block a:hover { /***** Media query print: Do not print the Toolbar. *****/ @media print { .sf-toolbar { - display: none; + display: none !important; } } From ba31d0ee5995049f8926502554e6075317a2edf8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 16 Oct 2020 15:25:24 +0200 Subject: [PATCH 024/146] [DoctrinBridge] make Uid types stricter --- .../Tests/Types/UlidBinaryTypeTest.php | 16 +++---- .../Doctrine/Tests/Types/UlidTypeTest.php | 40 +++++++---------- .../Tests/Types/UuidBinaryTypeTest.php | 18 +++----- .../Doctrine/Tests/Types/UuidTypeTest.php | 37 +++++++--------- .../Doctrine/Types/AbstractBinaryUidType.php | 40 ++++++----------- .../Bridge/Doctrine/Types/AbstractUidType.php | 44 ++++++++----------- 6 files changed, 74 insertions(+), 121 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidBinaryTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidBinaryTypeTest.php index fce1aa6100953..8ea165b49769a 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidBinaryTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidBinaryTypeTest.php @@ -52,24 +52,18 @@ public function testUlidConvertsToDatabaseValue() $this->assertEquals($expected, $actual); } - public function testStringUlidConvertsToDatabaseValue() - { - $expected = Ulid::fromString(self::DUMMY_ULID)->toBinary(); - $actual = $this->type->convertToDatabaseValue(self::DUMMY_ULID, $this->platform); - - $this->assertEquals($expected, $actual); - } - - public function testInvalidUlidConversionForDatabaseValue() + public function testNotSupportedStringUlidConversionToDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue('abcdefg', $this->platform); + $this->type->convertToDatabaseValue(self::DUMMY_ULID, $this->platform); } public function testNotSupportedTypeConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(new \stdClass(), $this->platform)); + $this->expectException(ConversionException::class); + + $this->type->convertToDatabaseValue(new \stdClass(), $this->platform); } public function testNullConversionForDatabaseValue() diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php index 328df993b2690..43715bb2324a1 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php @@ -44,7 +44,7 @@ protected function setUp(): void $this->type = Type::getType('ulid'); } - public function testUlidConvertsToDatabaseValue(): void + public function testUlidConvertsToDatabaseValue() { $ulid = Ulid::fromString(self::DUMMY_ULID); @@ -54,7 +54,7 @@ public function testUlidConvertsToDatabaseValue(): void $this->assertEquals($expected, $actual); } - public function testUlidInterfaceConvertsToDatabaseValue(): void + public function testUlidInterfaceConvertsToDatabaseValue() { $ulid = $this->createMock(AbstractUid::class); @@ -68,34 +68,26 @@ public function testUlidInterfaceConvertsToDatabaseValue(): void $this->assertEquals('foo', $actual); } - public function testUlidStringConvertsToDatabaseValue(): void - { - $actual = $this->type->convertToDatabaseValue(self::DUMMY_ULID, $this->platform); - $ulid = Ulid::fromString(self::DUMMY_ULID); - - $expected = $ulid->toRfc4122(); - - $this->assertEquals($expected, $actual); - } - - public function testInvalidUlidConversionForDatabaseValue(): void + public function testNotSupportedUlidStringConversionToDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue('abcdefg', $this->platform); + $this->type->convertToDatabaseValue(self::DUMMY_ULID, $this->platform); } public function testNotSupportedTypeConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(new \stdClass(), $this->platform)); + $this->expectException(ConversionException::class); + + $this->type->convertToDatabaseValue(new \stdClass(), $this->platform); } - public function testNullConversionForDatabaseValue(): void + public function testNullConversionForDatabaseValue() { $this->assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } - public function testUlidInterfaceConvertsToPHPValue(): void + public function testUlidInterfaceConvertsToPHPValue() { $ulid = $this->createMock(AbstractUid::class); $actual = $this->type->convertToPHPValue($ulid, $this->platform); @@ -103,7 +95,7 @@ public function testUlidInterfaceConvertsToPHPValue(): void $this->assertSame($ulid, $actual); } - public function testUlidConvertsToPHPValue(): void + public function testUlidConvertsToPHPValue() { $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, $this->platform); @@ -111,36 +103,36 @@ public function testUlidConvertsToPHPValue(): void $this->assertEquals(self::DUMMY_ULID, $ulid->__toString()); } - public function testInvalidUlidConversionForPHPValue(): void + public function testInvalidUlidConversionForPHPValue() { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } - public function testNullConversionForPHPValue(): void + public function testNullConversionForPHPValue() { $this->assertNull($this->type->convertToPHPValue(null, $this->platform)); } - public function testReturnValueIfUlidForPHPValue(): void + public function testReturnValueIfUlidForPHPValue() { $ulid = new Ulid(); $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, $this->platform)); } - public function testGetName(): void + public function testGetName() { $this->assertEquals('ulid', $this->type->getName()); } - public function testGetGuidTypeDeclarationSQL(): void + public function testGetGuidTypeDeclarationSQL() { $this->assertEquals('DUMMYVARCHAR()', $this->type->getSqlDeclaration(['length' => 36], $this->platform)); } - public function testRequiresSQLCommentHint(): void + public function testRequiresSQLCommentHint() { $this->assertTrue($this->type->requiresSQLCommentHint($this->platform)); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidBinaryTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidBinaryTypeTest.php index 9e68b6caed3a6..7d38606cf9054 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidBinaryTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidBinaryTypeTest.php @@ -52,21 +52,11 @@ public function testUuidConvertsToDatabaseValue() $this->assertEquals($expected, $actual); } - public function testStringUuidConvertsToDatabaseValue() - { - $uuid = self::DUMMY_UUID; - - $expected = uuid_parse(self::DUMMY_UUID); - $actual = $this->type->convertToDatabaseValue($uuid, $this->platform); - - $this->assertEquals($expected, $actual); - } - - public function testInvalidUuidConversionForDatabaseValue() + public function testNotSupportedStringUuidConversionToDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue('abcdefg', $this->platform); + $this->type->convertToDatabaseValue(self::DUMMY_UUID, $this->platform); } public function testNullConversionForDatabaseValue() @@ -90,7 +80,9 @@ public function testInvalidUuidConversionForPHPValue() public function testNotSupportedTypeConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(new \stdClass(), $this->platform)); + $this->expectException(ConversionException::class); + + $this->type->convertToDatabaseValue(new \stdClass(), $this->platform); } public function testNullConversionForPHPValue() diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php index a61526cc3dc10..c5c6658dad7bd 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UuidTypeTest.php @@ -44,7 +44,7 @@ protected function setUp(): void $this->type = Type::getType('uuid'); } - public function testUuidConvertsToDatabaseValue(): void + public function testUuidConvertsToDatabaseValue() { $uuid = Uuid::fromString(self::DUMMY_UUID); @@ -54,7 +54,7 @@ public function testUuidConvertsToDatabaseValue(): void $this->assertEquals($expected, $actual); } - public function testUuidInterfaceConvertsToDatabaseValue(): void + public function testUuidInterfaceConvertsToDatabaseValue() { $uuid = $this->createMock(AbstractUid::class); @@ -68,31 +68,26 @@ public function testUuidInterfaceConvertsToDatabaseValue(): void $this->assertEquals('foo', $actual); } - public function testUuidStringConvertsToDatabaseValue(): void - { - $actual = $this->type->convertToDatabaseValue(self::DUMMY_UUID, $this->platform); - - $this->assertEquals(self::DUMMY_UUID, $actual); - } - - public function testInvalidUuidConversionForDatabaseValue(): void + public function testNotSupportedUuidStringConversionToDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue('abcdefg', $this->platform); + $this->type->convertToDatabaseValue(self::DUMMY_UUID, $this->platform); } public function testNotSupportedTypeConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(new \stdClass(), $this->platform)); + $this->expectException(ConversionException::class); + + $this->type->convertToDatabaseValue(new \stdClass(), $this->platform); } - public function testNullConversionForDatabaseValue(): void + public function testNullConversionForDatabaseValue() { $this->assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } - public function testUuidInterfaceConvertsToPHPValue(): void + public function testUuidInterfaceConvertsToPHPValue() { $uuid = $this->createMock(AbstractUid::class); $actual = $this->type->convertToPHPValue($uuid, $this->platform); @@ -100,7 +95,7 @@ public function testUuidInterfaceConvertsToPHPValue(): void $this->assertSame($uuid, $actual); } - public function testUuidConvertsToPHPValue(): void + public function testUuidConvertsToPHPValue() { $uuid = $this->type->convertToPHPValue(self::DUMMY_UUID, $this->platform); @@ -108,36 +103,36 @@ public function testUuidConvertsToPHPValue(): void $this->assertEquals(self::DUMMY_UUID, $uuid->__toString()); } - public function testInvalidUuidConversionForPHPValue(): void + public function testInvalidUuidConversionForPHPValue() { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } - public function testNullConversionForPHPValue(): void + public function testNullConversionForPHPValue() { $this->assertNull($this->type->convertToPHPValue(null, $this->platform)); } - public function testReturnValueIfUuidForPHPValue(): void + public function testReturnValueIfUuidForPHPValue() { $uuid = Uuid::v4(); $this->assertSame($uuid, $this->type->convertToPHPValue($uuid, $this->platform)); } - public function testGetName(): void + public function testGetName() { $this->assertEquals('uuid', $this->type->getName()); } - public function testGetGuidTypeDeclarationSQL(): void + public function testGetGuidTypeDeclarationSQL() { $this->assertEquals('DUMMYVARCHAR()', $this->type->getSqlDeclaration(['length' => 36], $this->platform)); } - public function testRequiresSQLCommentHint(): void + public function testRequiresSQLCommentHint() { $this->assertTrue($this->type->requiresSQLCommentHint($this->platform)); } diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractBinaryUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractBinaryUidType.php index 587f9a54f3f0c..9321d148ce3be 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractBinaryUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractBinaryUidType.php @@ -13,21 +13,19 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; -use Doctrine\DBAL\Types\GuidType; +use Doctrine\DBAL\Types\Type; use Symfony\Component\Uid\AbstractUid; -abstract class AbstractBinaryUidType extends GuidType +abstract class AbstractBinaryUidType extends Type { abstract protected function getUidClass(): string; public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { - return $platform->getBinaryTypeDeclarationSQL( - [ - 'length' => '16', - 'fixed' => true, - ] - ); + return $platform->getBinaryTypeDeclarationSQL([ + 'length' => '16', + 'fixed' => true, + ]); } /** @@ -37,21 +35,19 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla */ public function convertToPHPValue($value, AbstractPlatform $platform): ?AbstractUid { - if (null === $value || '' === $value) { - return null; + if ($value instanceof AbstractUid || null === $value) { + return $value; } - if ($value instanceof AbstractUid) { - return $value; + if (!\is_string($value)) { + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); } try { - $uuid = $this->getUidClass()::fromString($value); + return $this->getUidClass()::fromString($value); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); + throw ConversionException::conversionFailed($value, $this->getName(), $e); } - - return $uuid; } /** @@ -61,23 +57,15 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Abstract */ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { - if (null === $value || '' === $value) { - return null; - } - if ($value instanceof AbstractUid) { return $value->toBinary(); } - if (!\is_string($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + if (null === $value) { return null; } - try { - return $this->getUidClass()::fromString((string) $value)->toBinary(); - } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); - } + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', AbstractUid::class]); } /** diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php index 2286bb7268191..a14eb853e3868 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php @@ -13,13 +13,21 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; -use Doctrine\DBAL\Types\GuidType; +use Doctrine\DBAL\Types\Type; use Symfony\Component\Uid\AbstractUid; -abstract class AbstractUidType extends GuidType +abstract class AbstractUidType extends Type { abstract protected function getUidClass(): string; + /** + * {@inheritdoc} + */ + public function getSQLDeclaration(array $column, AbstractPlatform $platform): string + { + return $platform->getGuidTypeDeclarationSQL($column); + } + /** * {@inheritdoc} * @@ -27,21 +35,19 @@ abstract protected function getUidClass(): string; */ public function convertToPHPValue($value, AbstractPlatform $platform): ?AbstractUid { - if (null === $value || '' === $value) { - return null; + if ($value instanceof AbstractUid || null === $value) { + return $value; } - if ($value instanceof AbstractUid) { - return $value; + if (!\is_string($value)) { + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); } try { - $uuid = $this->getUidClass()::fromString($value); + return $this->getUidClass()::fromString($value); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); + throw ConversionException::conversionFailed($value, $this->getName(), $e); } - - return $uuid; } /** @@ -51,29 +57,15 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Abstract */ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { - if (null === $value || '' === $value) { - return null; - } - if ($value instanceof AbstractUid) { return $value->toRfc4122(); } - if (!\is_string($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + if (null === $value) { return null; } - if ($this->getUidClass()::isValid((string) $value)) { - try { - $uuid = $this->getUidClass()::fromString($value); - - return $uuid->toRfc4122(); - } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); - } - } - - throw ConversionException::conversionFailed($value, $this->getName()); + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', AbstractUid::class]); } /** From 5d9d62cf4c65d7c18d353ed7b4d9acfa7b6c4219 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 17 Oct 2020 12:36:42 +0200 Subject: [PATCH 025/146] Bump APCu to 5.1.19 on Travis. --- .travis.yml | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6765f45f3dd00..71c306e3786b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -142,23 +142,6 @@ before_install: } export -f tpecl - install_apcu_dev () { - local ref=$1 - local INI=$2 - - wget https://github.com/krakjoe/apcu/archive/${ref}.zip - unzip ${ref}.zip - cd apcu-${ref} - phpize - ./configure - make - mv modules/apcu.so $(php -r "echo ini_get('extension_dir');") - echo 'extension = apcu.so' >> $INI - cd .. - rm -rf apcu-${ref} ${ref}.zip - } - export -f install_apcu_dev - - | # Install sigchild-enabled PHP to test the Process component on the lowest PHP matrix line if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then @@ -200,11 +183,11 @@ before_install: [[ -e $ext_cache ]] || (tfold ext.symfony_debug "cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && mv modules/symfony_debug.so $ext_cache && phpize --clean") echo extension = $ext_cache >> $INI elif [[ $PHP = 7.* ]]; then - tfold ext.apcu tpecl apcu-5.1.17 apcu.so $INI + tfold ext.apcu tpecl apcu-5.1.19 apcu.so $INI tfold ext.mongodb tpecl mongodb-1.6.0 mongodb.so $INI elif [[ $PHP = nightly ]]; then tfold ext.memcached tpecl memcached-3.1.5 memcached.so $INI - tfold ext.apcu install_apcu_dev 9c36db45100d4d27ec33072f4be90f1f5a0108b7 $INI + tfold ext.apcu tpecl apcu-5.1.19 apcu.so $INI fi done From 1058e19ab4bbb8cbfb549a550938e36ae5d8b34a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 17 Oct 2020 18:04:15 +0200 Subject: [PATCH 026/146] Bump igbinary to v3.1.6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 887adc809cc3f..df62dcc4fac8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -183,7 +183,7 @@ before_install: tfold ext.redis tpecl redis-5.2.2 redis.so $INI "no" fi - tfold ext.igbinary tpecl igbinary-3.1.5 igbinary.so $INI + tfold ext.igbinary tpecl igbinary-3.1.6 igbinary.so $INI done - | # List all php extensions with versions From c4cc4a338b9e754fb5c079bbbd17b9895c832f4e Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 18 Oct 2020 02:10:46 +0200 Subject: [PATCH 027/146] [Messenger][Doctrine] Avoid early db access for pgsql detection --- .../Bridge/Doctrine/Transport/DoctrineTransportFactory.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php index 224d8bafad75f..27759ec3b03a4 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; +use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver; use Doctrine\Persistence\ConnectionRegistry; use Symfony\Bridge\Doctrine\RegistryInterface; use Symfony\Component\Messenger\Exception\TransportException; @@ -47,7 +48,7 @@ public function createTransport(string $dsn, array $options, SerializerInterface throw new TransportException(sprintf('Could not find Doctrine connection from Messenger DSN "%s".', $dsn), 0, $e); } - if ($useNotify && ($wrappedConnection = $driverConnection->getWrappedConnection()) && method_exists($wrappedConnection, 'pgsqlGetNotify')) { + if ($useNotify && $driverConnection->getDriver() instanceof AbstractPostgreSQLDriver) { $connection = new PostgreSqlConnection($configuration, $driverConnection); } else { $connection = new Connection($configuration, $driverConnection); From 43c05774ac344eb7556fad085fc7905605843bbe Mon Sep 17 00:00:00 2001 From: Dieter Date: Sat, 17 Oct 2020 20:52:38 +0200 Subject: [PATCH 028/146] Allow setting AMQP option "login" --- .../Component/Messenger/Bridge/Amqp/Transport/Connection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index adf26446ade9e..ac5c999303f17 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -37,6 +37,7 @@ class Connection 'port', 'vhost', 'user', + 'login', 'password', 'queues', 'exchange', @@ -123,7 +124,7 @@ public function __construct(array $connectionOptions, array $exchangeOptions, ar * * host: Hostname of the AMQP service * * port: Port of the AMQP service * * vhost: Virtual Host to use with the AMQP service - * * user: Username to use to connect the AMQP service + * * user|login: Username to use to connect the AMQP service * * password: Password to use to connect to the AMQP service * * read_timeout: Timeout in for income activity. Note: 0 or greater seconds. May be fractional. * * write_timeout: Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. From a246894a005049f98aa5106770250ca90f3ab0ca Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Sun, 18 Oct 2020 18:14:51 -0400 Subject: [PATCH 029/146] fix RequestRateLimiterInterface::reset() --- .../HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php | 2 +- .../HttpFoundation/RateLimiter/RequestRateLimiterInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php index 430c150ca0934..cf6d1e1bc3c56 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php @@ -45,7 +45,7 @@ public function consume(Request $request): Limit return $minimalLimit; } - public function reset(): void + public function reset(Request $request): void { foreach ($this->getLimiters($request) as $limiter) { $limiter->reset(); diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php index 21d7637710ba8..d37427760018b 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php @@ -28,5 +28,5 @@ interface RequestRateLimiterInterface { public function consume(Request $request): Limit; - public function reset(): void; + public function reset(Request $request): void; } From 301f0aa0db9c5570316cb9a6eb433c0c5c0e7b52 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 18 Oct 2020 13:22:38 +0200 Subject: [PATCH 030/146] Added missing invalid messages --- .../Form/Extension/Core/Type/WeekType.php | 3 +++ .../Resources/translations/validators.en.xlf | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php b/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php index bae115756afca..f11d942fab985 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php @@ -155,6 +155,9 @@ public function configureOptions(OptionsResolver $resolver) }, 'compound' => $compound, 'choice_translation_domain' => false, + 'invalid_message' => static function (Options $options, $previousValue) { + return ($options['legacy_error_messages'] ?? true) ? $previousValue : 'Please enter a valid week.'; + }, ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); diff --git a/src/Symfony/Component/Form/Resources/translations/validators.en.xlf b/src/Symfony/Component/Form/Resources/translations/validators.en.xlf index 97ed83fd47425..e556c40b647f6 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.en.xlf @@ -114,6 +114,26 @@ Please provide a valid phone number. Please provide a valid phone number. + + The checkbox has an invalid value. + The checkbox has an invalid value. + + + Please enter a valid email address. + Please enter a valid email address. + + + Please select a valid option. + Please select a valid option. + + + Please select a valid range. + Please select a valid range. + + + Please enter a valid week. + Please enter a valid week. + From 86c78b630240b1b8b60d5e66e872a7794d62676a Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 18 Oct 2020 13:23:08 +0200 Subject: [PATCH 031/146] Added dutch translations for new invalid messages --- .../Resources/translations/validators.nl.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf index 3d737d79c1d56..7aa56ebf1bda4 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. De CSRF-token is ongeldig. Probeer het formulier opnieuw te versturen. + + This value is not a valid HTML5 color. + Dit is geen geldige HTML5 kleur. + + + Please enter a valid birthdate. + Vul een geldige geboortedatum in. + + + The selected choice is invalid. + Deze keuze is ongeldig. + + + The collection is invalid. + Deze collectie is ongeldig. + + + Please select a valid color. + Kies een geldige kleur. + + + Please select a valid country. + Kies een geldige landnaam. + + + Please select a valid currency. + Kies een geldige valuta. + + + Please choose a valid date interval. + Kies een geldig tijdinterval. + + + Please enter a valid date and time. + Vul een geldige datum en tijd in. + + + Please enter a valid date. + Vul een geldige datum in. + + + Please select a valid file. + Kies een geldig bestand. + + + The hidden field is invalid. + Het verborgen veld is incorrect. + + + Please enter an integer. + Vul een geldig getal in. + + + Please select a valid language. + Kies een geldige taal. + + + Please select a valid locale. + Kies een geldige locale. + + + Please enter a valid money amount. + Vul een geldig bedrag in. + + + Please enter a number. + Vul een geldig getal in. + + + The password is invalid. + Het wachtwoord is incorrect. + + + Please enter a percentage value. + Vul een geldig percentage in. + + + The values do not match. + De waardes komen niet overeen. + + + Please enter a valid time. + Vul een geldige tijd in. + + + Please select a valid timezone. + Vul een geldige tijdzone in. + + + Please enter a valid URL. + Vul een geldige URL in. + + + Please enter a valid search term. + Vul een geldige zoekterm in. + + + Please provide a valid phone number. + Vul een geldig telefoonnummer in. + + + The checkbox has an invalid value. + De checkbox heeft een incorrecte waarde. + + + Please enter a valid email address. + Vul een geldig e-mailadres in. + + + Please select a valid option. + Kies een geldige optie. + + + Please select a valid range. + Kies een geldig bereik. + + + Please enter a valid week. + Vul een geldige week in. + From e3489d9b58b1e683a34b8e45d02e4c54e171094e Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 18 Oct 2020 13:29:30 +0200 Subject: [PATCH 032/146] Stop using set-env in GitHub actions. --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9a962f23b33e6..8146c127ec1aa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,8 +58,8 @@ jobs: run: | ([ -d ~/.composer ] || mkdir ~/.composer) && cp .github/composer-config.json ~/.composer/config.json SYMFONY_VERSION=$(cat composer.json | grep '^ *\"branch-version\". *\"[1-9]' | grep -o '[0-9.]*') - echo "::set-env name=SYMFONY_VERSION::$SYMFONY_VERSION" - echo "::set-env name=COMPOSER_ROOT_VERSION::$SYMFONY_VERSION.x-dev" + echo "SYMFONY_VERSION=$SYMFONY_VERSION" >> $GITHUB_ENV + echo "COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev" >> $GITHUB_ENV - name: Determine composer cache directory id: composer-cache From 56809d1b913e355fe4cca57882b6d3d847959e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 6 Oct 2020 09:12:33 +0200 Subject: [PATCH 033/146] Parameterize list of retryed Http methods --- .../DependencyInjection/Configuration.php | 38 +++++++++- .../FrameworkExtension.php | 12 ++- .../Resources/config/schema/symfony-1.0.xsd | 9 ++- .../Fixtures/php/http_client_retry.php | 2 +- .../Fixtures/xml/http_client_retry.xml | 7 +- .../Fixtures/yml/http_client_retry.yml | 4 +- .../FrameworkExtensionTest.php | 2 +- .../HttpClient/Retry/GenericRetryStrategy.php | 35 ++++++++- .../HttpClient/RetryableHttpClient.php | 73 ++++++++++++------- .../Tests/Retry/GenericRetryStrategyTest.php | 34 +++++++-- 10 files changed, 170 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0d4ee4f797528..c9287c4664255 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1654,13 +1654,43 @@ private function addHttpClientRetrySection() ->performNoDeepMerging() ->beforeNormalization() ->ifArray() - ->then(function ($v) { - return array_filter(array_values($v)); + ->then(static function ($v) { + $list = []; + foreach ($v as $key => $val) { + if (is_numeric($val)) { + $list[] = ['code' => $val]; + } elseif (\is_array($val)) { + if (isset($val['code']) || isset($val['methods'])) { + $list[] = $val; + } else { + $list[] = ['code' => $key, 'methods' => $val]; + } + } elseif (true === $val || null === $val) { + $list[] = ['code' => $key]; + } + } + + return $list; }) ->end() - ->prototype('integer')->end() + ->useAttributeAsKey('code') + ->arrayPrototype() + ->fixXmlConfig('method') + ->children() + ->integerNode('code')->end() + ->arrayNode('methods') + ->beforeNormalization() + ->ifArray() + ->then(function ($v) { + return array_map('strtoupper', $v); + }) + ->end() + ->prototype('scalar')->end() + ->info('A list of HTTP methods that triggers a retry for this status code. When empty, all methods are retried') + ->end() + ->end() + ->end() ->info('A list of HTTP status code that triggers a retry') - ->defaultValue([423, 425, 429, 500, 502, 503, 504, 507, 510]) ->end() ->integerNode('max_retries')->defaultValue(3)->min(0)->end() ->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index eb6aeb2c323b4..a05faf1200009 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -64,6 +64,7 @@ use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; use Symfony\Component\HttpClient\RetryableHttpClient; use Symfony\Component\HttpClient\ScopingHttpClient; use Symfony\Component\HttpFoundation\Request; @@ -2072,8 +2073,17 @@ private function registerRetryableHttpClient(array $options, string $name, Conta $retryStrategy = new Reference($options['retry_strategy']); } else { $retryStrategy = new ChildDefinition('http_client.abstract_retry_strategy'); + $codes = []; + foreach ($options['http_codes'] as $code => $codeOptions) { + if ($codeOptions['methods']) { + $codes[$code] = $codeOptions['methods']; + } else { + $codes[] = $code; + } + } + $retryStrategy - ->replaceArgument(0, $options['http_codes']) + ->replaceArgument(0, $codes ?: GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES) ->replaceArgument(1, $options['delay']) ->replaceArgument(2, $options['multiplier']) ->replaceArgument(3, $options['max_delay']) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 93058d190de22..61410d874cd05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -578,7 +578,7 @@ - + @@ -590,6 +590,13 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_retry.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_retry.php index 206db6b02af92..3260ac56a7510 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_retry.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_retry.php @@ -5,7 +5,7 @@ 'default_options' => [ 'retry_failed' => [ 'retry_strategy' => null, - 'http_codes' => [429, 500], + 'http_codes' => [429, 500 => ['GET', 'HEAD']], 'max_retries' => 2, 'delay' => 100, 'multiplier' => 2, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_retry.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_retry.xml index 76004166a16b3..eb7798914488b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_retry.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_retry.xml @@ -14,8 +14,11 @@ max-retries="2" multiplier="2" jitter="0.3"> - 429 - 500 + + + GET + HEAD + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_retry.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_retry.yml index 0ef87bad38b49..eba686819c300 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_retry.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_retry.yml @@ -3,7 +3,9 @@ framework: default_options: retry_failed: retry_strategy: null - http_codes: [429, 500] + http_codes: + 429: true + 500: ['GET', 'HEAD'] max_retries: 2 delay: 100 multiplier: 2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 22a6027b7c99e..fdb1d5a6014a5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1500,7 +1500,7 @@ public function testHttpClientRetry() } $container = $this->createContainerFromFile('http_client_retry'); - $this->assertSame([429, 500], $container->getDefinition('http_client.retry_strategy')->getArgument(0)); + $this->assertSame([429, 500 => ['GET', 'HEAD']], $container->getDefinition('http_client.retry_strategy')->getArgument(0)); $this->assertSame(100, $container->getDefinition('http_client.retry_strategy')->getArgument(1)); $this->assertSame(2, $container->getDefinition('http_client.retry_strategy')->getArgument(2)); $this->assertSame(0, $container->getDefinition('http_client.retry_strategy')->getArgument(3)); diff --git a/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php b/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php index 14727f7584ad6..ebe10a2186962 100644 --- a/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php +++ b/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient\Retry; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\Response\AsyncContext; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; @@ -21,7 +22,19 @@ */ class GenericRetryStrategy implements RetryStrategyInterface { - public const DEFAULT_RETRY_STATUS_CODES = [423, 425, 429, 500, 502, 503, 504, 507, 510]; + public const IDEMPOTENT_METHODS = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']; + public const DEFAULT_RETRY_STATUS_CODES = [ + 0 => self::IDEMPOTENT_METHODS, // for transport exceptions + 423, + 425, + 429, + 500 => self::IDEMPOTENT_METHODS, + 502, + 503, + 504 => self::IDEMPOTENT_METHODS, + 507 => self::IDEMPOTENT_METHODS, + 510 => self::IDEMPOTENT_METHODS, + ]; private $statusCodes; private $delayMs; @@ -63,7 +76,25 @@ public function __construct(array $statusCodes = self::DEFAULT_RETRY_STATUS_CODE public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool { - return \in_array($context->getStatusCode(), $this->statusCodes, true); + $statusCode = $context->getStatusCode(); + if (\in_array($statusCode, $this->statusCodes, true)) { + return true; + } + if (isset($this->statusCodes[$statusCode]) && \is_array($this->statusCodes[$statusCode])) { + return \in_array($context->getInfo('http_method'), $this->statusCodes[$statusCode], true); + } + if (null === $exception) { + return false; + } + + if (\in_array(0, $this->statusCodes, true)) { + return true; + } + if (isset($this->statusCodes[0]) && \is_array($this->statusCodes[0])) { + return \in_array($context->getInfo('http_method'), $this->statusCodes[0], true); + } + + return false; } public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php index 6cf932e60a901..6bca91e4f1dd3 100644 --- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php +++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php @@ -68,44 +68,63 @@ public function request(string $method, string $url, array $options = []): Respo // catch TransportExceptionInterface to send it to the strategy $context->setInfo('retry_count', $retryCount); } + if (null !== $exception) { + // always retry request that fail to resolve DNS + if ('' !== $context->getInfo('primary_ip')) { + $shouldRetry = $this->strategy->shouldRetry($context, null, $exception); + if (null === $shouldRetry) { + throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with an exception.', \get_class($this->decider))); + } - if (null === $exception) { - if ($chunk->isFirst()) { - $context->setInfo('retry_count', $retryCount); - - if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) { + if (false === $shouldRetry) { $context->passthru(); - yield $chunk; + if (null !== $firstChunk) { + yield $firstChunk; + yield $context->createChunk($content); + yield $chunk; + } else { + yield $chunk; + } + $content = ''; return; } + } + } elseif ($chunk->isFirst()) { + $context->setInfo('retry_count', $retryCount); - // Body is needed to decide - if (null === $shouldRetry) { - $firstChunk = $chunk; - $content = ''; + if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) { + $context->passthru(); + yield $chunk; - return; - } - } else { - $content .= $chunk->getContent(); + return; + } - if (!$chunk->isLast()) { - return; - } + // Body is needed to decide + if (null === $shouldRetry) { + $firstChunk = $chunk; + $content = ''; - if (null === $shouldRetry = $this->strategy->shouldRetry($context, $content, null)) { - throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with a body.', \get_class($this->strategy))); - } + return; + } + } else { + $content .= $chunk->getContent(); - if (false === $shouldRetry) { - $context->passthru(); - yield $firstChunk; - yield $context->createChunk($content); - $content = ''; + if (!$chunk->isLast()) { + return; + } - return; - } + if (null === $shouldRetry = $this->strategy->shouldRetry($context, $content, null)) { + throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with a body.', \get_class($this->strategy))); + } + + if (false === $shouldRetry) { + $context->passthru(); + yield $firstChunk; + yield $context->createChunk($content); + $content = ''; + + return; } } diff --git a/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php b/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php index ecb84cb482ec7..e04cdb45b6811 100644 --- a/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php @@ -12,25 +12,47 @@ namespace Symfony\Component\HttpClient\Tests\Retry; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\AsyncContext; use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class GenericRetryStrategyTest extends TestCase { - public function testShouldRetryStatusCode() + /** + * @dataProvider provideRetryable + */ + public function testShouldRetry(string $method, int $code, ?TransportExceptionInterface $exception) + { + $strategy = new GenericRetryStrategy(); + + self::assertTrue($strategy->shouldRetry($this->getContext(0, $method, 'http://example.com/', $code), null, $exception)); + } + + /** + * @dataProvider provideNotRetryable + */ + public function testShouldNotRetry(string $method, int $code, ?TransportExceptionInterface $exception) { - $strategy = new GenericRetryStrategy([500]); + $strategy = new GenericRetryStrategy(); - self::assertTrue($strategy->shouldRetry($this->getContext(0, 'GET', 'http://example.com/', 500), null, null)); + self::assertFalse($strategy->shouldRetry($this->getContext(0, $method, 'http://example.com/', $code), null, $exception)); } - public function testIsNotRetryableOk() + public function provideRetryable(): iterable { - $strategy = new GenericRetryStrategy([500]); + yield ['GET', 200, new TransportException()]; + yield ['GET', 500, null]; + yield ['POST', 429, null]; + } - self::assertFalse($strategy->shouldRetry($this->getContext(0, 'GET', 'http://example.com/', 200), null, null)); + public function provideNotRetryable(): iterable + { + yield ['POST', 200, null]; + yield ['POST', 200, new TransportException()]; + yield ['POST', 500, null]; } /** From f4a99b236170495f362ff6601652ba2a65a023cb Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 19 Oct 2020 23:16:40 +0200 Subject: [PATCH 034/146] Don't skip Doctrine tests on php 8. --- .../Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php | 7 ------- .../Security/RememberMe/DoctrineTokenProviderTest.php | 7 ------- .../Tests/Security/User/EntityUserProviderTest.php | 7 ------- .../Validator/Constraints/UniqueEntityValidatorTest.php | 7 ------- .../SecurityBundle/Tests/Functional/SetAclCommandTest.php | 7 ------- .../Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php | 5 ----- .../Component/Cache/Tests/Simple/PdoDbalCacheTest.php | 5 ----- 7 files changed, 45 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 1d382a95aa65c..8475cff456afa 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -61,13 +61,6 @@ class EntityTypeTest extends BaseTypeTest protected static $supportedFeatureSetVersion = 304; - public static function setUpBeforeClass() - { - if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - protected function setUp() { $this->em = DoctrineTestHelper::createTestEntityManager(); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php index 73588ce2bba50..6e406b06b76af 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php @@ -13,13 +13,6 @@ */ class DoctrineTokenProviderTest extends TestCase { - public static function setUpBeforeClass() - { - if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - public function testCreateNewToken() { $provider = $this->bootstrapProvider(); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index e43940d85c32d..8916f8fb929e0 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -23,13 +23,6 @@ class EntityUserProviderTest extends TestCase { - public static function setUpBeforeClass() - { - if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - public function testRefreshUserGetsUserByPrimaryKey() { $em = DoctrineTestHelper::createTestEntityManager(); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index ba772e58fd047..77d15999905ba 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -63,13 +63,6 @@ class UniqueEntityValidatorTest extends ConstraintValidatorTestCase protected $repositoryFactory; - public static function setUpBeforeClass() - { - if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - protected function setUp() { $this->repositoryFactory = new TestRepositoryFactory(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php index 892a51f9bd27c..8eb70c09c1ed7 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php @@ -40,13 +40,6 @@ class SetAclCommandTest extends AbstractWebTestCase const OBJECT_CLASS = 'Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle\Entity\Car'; const SECURITY_CLASS = 'Symfony\Component\Security\Core\User\User'; - public static function setUpBeforeClass() - { - if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - public function testSetAclUser() { $objectId = 1; diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php index 351972da48691..aa53958cfab32 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Version; use Symfony\Component\Cache\Adapter\PdoAdapter; use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; @@ -31,10 +30,6 @@ public static function setUpBeforeClass() self::markTestSkipped('Extension pdo_sqlite required.'); } - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); $pool = new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile])); diff --git a/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php index 79fd97a752a2e..4da2b603cf88f 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Cache\Tests\Simple; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Version; use Symfony\Component\Cache\Simple\PdoCache; use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; @@ -31,10 +30,6 @@ public static function setUpBeforeClass() self::markTestSkipped('Extension pdo_sqlite required.'); } - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); $pool = new PdoCache(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile])); From c65c6ea75de5e950970d8f8ed4981db9f728800a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 20 Oct 2020 00:13:18 +0200 Subject: [PATCH 035/146] Don't skip Doctrine tests on php 8. --- .../Component/Cache/Tests/Adapter/PdoAdapterTest.php | 5 ----- .../Component/Lock/Tests/Store/PdoDbalStoreTest.php | 5 ----- src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php | 5 ----- .../Tests/Transport/Doctrine/DoctrineIntegrationTest.php | 8 -------- 4 files changed, 23 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php index 9056c848718bb..dbd93bdd71f03 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Cache\Tests\Adapter; -use Doctrine\DBAL\Version; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\PdoAdapter; use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; @@ -31,10 +30,6 @@ public static function setUpBeforeClass(): void self::markTestSkipped('Extension pdo_sqlite required.'); } - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); $pool = new PdoAdapter('sqlite:'.self::$dbFile); diff --git a/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php index 829e8ec9f7616..264c99829c98f 100644 --- a/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Lock\Tests\Store; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Version; use Symfony\Component\Lock\PersistingStoreInterface; use Symfony\Component\Lock\Store\PdoStore; @@ -31,10 +30,6 @@ public static function setUpBeforeClass(): void { self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_lock'); - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - $store = new PdoStore(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile])); $store->createTable(); } diff --git a/src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php index f694363045300..800397d153d19 100644 --- a/src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Lock\Tests\Store; -use Doctrine\DBAL\Version; use Symfony\Component\Lock\Key; use Symfony\Component\Lock\PersistingStoreInterface; use Symfony\Component\Lock\Store\PdoStore; @@ -31,10 +30,6 @@ public static function setUpBeforeClass(): void { self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_lock'); - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - $store = new PdoStore('sqlite:'.self::$dbFile); $store->createTable(); } diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index b0f8e8f91140a..e88e00364701f 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -14,7 +14,6 @@ use Doctrine\DBAL\Driver\Result as DriverResult; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Result; -use Doctrine\DBAL\Version; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\Doctrine\Connection; @@ -31,13 +30,6 @@ class DoctrineIntegrationTest extends TestCase /** @var string */ private $sqliteFile; - public static function setUpBeforeClass(): void - { - if (\PHP_VERSION_ID >= 80000 && class_exists(Version::class)) { - self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); - } - } - protected function setUp(): void { $this->sqliteFile = sys_get_temp_dir().'/symfony.messenger.sqlite'; From 697fe21f24554cc5159b3c12c1fd13030bba3f8f Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 18 Oct 2020 13:23:08 +0200 Subject: [PATCH 036/146] Added dutch translations for new invalid messages --- .../Resources/translations/validators.nl.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf index 3d737d79c1d56..7aa56ebf1bda4 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. De CSRF-token is ongeldig. Probeer het formulier opnieuw te versturen. + + This value is not a valid HTML5 color. + Dit is geen geldige HTML5 kleur. + + + Please enter a valid birthdate. + Vul een geldige geboortedatum in. + + + The selected choice is invalid. + Deze keuze is ongeldig. + + + The collection is invalid. + Deze collectie is ongeldig. + + + Please select a valid color. + Kies een geldige kleur. + + + Please select a valid country. + Kies een geldige landnaam. + + + Please select a valid currency. + Kies een geldige valuta. + + + Please choose a valid date interval. + Kies een geldig tijdinterval. + + + Please enter a valid date and time. + Vul een geldige datum en tijd in. + + + Please enter a valid date. + Vul een geldige datum in. + + + Please select a valid file. + Kies een geldig bestand. + + + The hidden field is invalid. + Het verborgen veld is incorrect. + + + Please enter an integer. + Vul een geldig getal in. + + + Please select a valid language. + Kies een geldige taal. + + + Please select a valid locale. + Kies een geldige locale. + + + Please enter a valid money amount. + Vul een geldig bedrag in. + + + Please enter a number. + Vul een geldig getal in. + + + The password is invalid. + Het wachtwoord is incorrect. + + + Please enter a percentage value. + Vul een geldig percentage in. + + + The values do not match. + De waardes komen niet overeen. + + + Please enter a valid time. + Vul een geldige tijd in. + + + Please select a valid timezone. + Vul een geldige tijdzone in. + + + Please enter a valid URL. + Vul een geldige URL in. + + + Please enter a valid search term. + Vul een geldige zoekterm in. + + + Please provide a valid phone number. + Vul een geldig telefoonnummer in. + + + The checkbox has an invalid value. + De checkbox heeft een incorrecte waarde. + + + Please enter a valid email address. + Vul een geldig e-mailadres in. + + + Please select a valid option. + Kies een geldige optie. + + + Please select a valid range. + Kies een geldig bereik. + + + Please enter a valid week. + Vul een geldige week in. + From 280a27fc1624e2da35aca23cfd406e069c9e8b66 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 20 Oct 2020 08:12:11 +0200 Subject: [PATCH 037/146] [Form] Sync translations --- .../Resources/translations/validators.en.xlf | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.en.xlf b/src/Symfony/Component/Form/Resources/translations/validators.en.xlf index 97ed83fd47425..e556c40b647f6 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.en.xlf @@ -114,6 +114,26 @@ Please provide a valid phone number. Please provide a valid phone number. + + The checkbox has an invalid value. + The checkbox has an invalid value. + + + Please enter a valid email address. + Please enter a valid email address. + + + Please select a valid option. + Please select a valid option. + + + Please select a valid range. + Please select a valid range. + + + Please enter a valid week. + Please enter a valid week. + From c5361cfc58f0792c3794c95054c34520724584cf Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Fri, 16 Oct 2020 12:07:55 -0400 Subject: [PATCH 038/146] [RateLimiter] rename Limit to RateLimit and add RateLimit::getLimit() --- .../AbstractRequestRateLimiter.php | 14 +++++----- .../RequestRateLimiterInterface.php | 4 +-- .../Component/RateLimiter/CompoundLimiter.php | 12 ++++----- .../MaxWaitDurationExceededException.php | 12 ++++----- .../Exception/RateLimitExceededException.php | 21 +++++++++------ .../RateLimiter/FixedWindowLimiter.php | 12 ++++----- .../RateLimiter/LimiterInterface.php | 2 +- .../Component/RateLimiter/NoLimiter.php | 6 ++--- .../RateLimiter/{Limit.php => RateLimit.php} | 11 ++++++-- .../Component/RateLimiter/Reservation.php | 10 +++---- .../RateLimiter/SlidingWindowLimiter.php | 6 ++--- .../Tests/FixedWindowLimiterTest.php | 22 +++++++++------- .../{LimitTest.php => RateLimitTest.php} | 14 +++++----- .../Tests/SlidingWindowLimiterTest.php | 16 +++++++----- .../Tests/TokenBucketLimiterTest.php | 26 ++++++++++--------- .../RateLimiter/TokenBucketLimiter.php | 14 +++++----- 16 files changed, 110 insertions(+), 92 deletions(-) rename src/Symfony/Component/RateLimiter/{Limit.php => RateLimit.php} (87%) rename src/Symfony/Component/RateLimiter/Tests/{LimitTest.php => RateLimitTest.php} (67%) diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php index cf6d1e1bc3c56..f700ebcd8657c 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php @@ -12,9 +12,9 @@ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\Limit; use Symfony\Component\RateLimiter\LimiterInterface; use Symfony\Component\RateLimiter\NoLimiter; +use Symfony\Component\RateLimiter\RateLimit; /** * An implementation of RequestRateLimiterInterface that @@ -26,23 +26,23 @@ */ abstract class AbstractRequestRateLimiter implements RequestRateLimiterInterface { - public function consume(Request $request): Limit + public function consume(Request $request): RateLimit { $limiters = $this->getLimiters($request); if (0 === \count($limiters)) { $limiters = [new NoLimiter()]; } - $minimalLimit = null; + $minimalRateLimit = null; foreach ($limiters as $limiter) { - $limit = $limiter->consume(1); + $rateLimit = $limiter->consume(1); - if (null === $minimalLimit || $limit->getRemainingTokens() < $minimalLimit->getRemainingTokens()) { - $minimalLimit = $limit; + if (null === $minimalRateLimit || $rateLimit->getRemainingTokens() < $minimalRateLimit->getRemainingTokens()) { + $minimalRateLimit = $rateLimit; } } - return $minimalLimit; + return $minimalRateLimit; } public function reset(Request $request): void diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php index d37427760018b..c7d31ba5db015 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * A special type of limiter that deals with requests. @@ -26,7 +26,7 @@ */ interface RequestRateLimiterInterface { - public function consume(Request $request): Limit; + public function consume(Request $request): RateLimit; public function reset(Request $request): void; } diff --git a/src/Symfony/Component/RateLimiter/CompoundLimiter.php b/src/Symfony/Component/RateLimiter/CompoundLimiter.php index 6722e0b436e70..286940930326e 100644 --- a/src/Symfony/Component/RateLimiter/CompoundLimiter.php +++ b/src/Symfony/Component/RateLimiter/CompoundLimiter.php @@ -38,18 +38,18 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation throw new ReserveNotSupportedException(__CLASS__); } - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { - $minimalLimit = null; + $minimalRateLimit = null; foreach ($this->limiters as $limiter) { - $limit = $limiter->consume($tokens); + $rateLimit = $limiter->consume($tokens); - if (null === $minimalLimit || $limit->getRemainingTokens() < $minimalLimit->getRemainingTokens()) { - $minimalLimit = $limit; + if (null === $minimalRateLimit || $rateLimit->getRemainingTokens() < $minimalRateLimit->getRemainingTokens()) { + $minimalRateLimit = $rateLimit; } } - return $minimalLimit; + return $minimalRateLimit; } public function reset(): void diff --git a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php index 025103f7a8741..1eeec9de64193 100644 --- a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php +++ b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php @@ -11,7 +11,7 @@ namespace Symfony\Component\RateLimiter\Exception; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * @author Wouter de Jong @@ -20,17 +20,17 @@ */ class MaxWaitDurationExceededException extends \RuntimeException { - private $limit; + private $rateLimit; - public function __construct(string $message, Limit $limit, int $code = 0, ?\Throwable $previous = null) + public function __construct(string $message, RateLimit $rateLimit, int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); - $this->limit = $limit; + $this->rateLimit = $rateLimit; } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } } diff --git a/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php b/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php index f96516e653bb0..0cb10c750befe 100644 --- a/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php +++ b/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php @@ -11,7 +11,7 @@ namespace Symfony\Component\RateLimiter\Exception; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * @author Kevin Bond @@ -20,27 +20,32 @@ */ class RateLimitExceededException extends \RuntimeException { - private $limit; + private $rateLimit; - public function __construct(Limit $limit, $code = 0, \Throwable $previous = null) + public function __construct(RateLimit $rateLimit, $code = 0, \Throwable $previous = null) { parent::__construct('Rate Limit Exceeded', $code, $previous); - $this->limit = $limit; + $this->rateLimit = $rateLimit; } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } public function getRetryAfter(): \DateTimeImmutable { - return $this->limit->getRetryAfter(); + return $this->rateLimit->getRetryAfter(); } public function getRemainingTokens(): int { - return $this->limit->getRemainingTokens(); + return $this->rateLimit->getRemainingTokens(); + } + + public function getLimit(): int + { + return $this->rateLimit->getLimit(); } } diff --git a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php index 9164eb4ae55ee..bb0135d76980b 100644 --- a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php @@ -64,19 +64,19 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation if ($availableTokens >= $tokens) { $window->add($tokens); - $reservation = new Reservation($now, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); + $reservation = new Reservation($now, new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->limit)); } else { $remainingTokens = $tokens - $availableTokens; $waitDuration = $window->calculateTimeForTokens($remainingTokens); if (null !== $maxTime && $waitDuration > $maxTime) { // process needs to wait longer than set interval - throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->limit)); } $window->add($tokens); - $reservation = new Reservation($now + $waitDuration, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + $reservation = new Reservation($now + $waitDuration, new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->limit)); } $this->storage->save($window); } finally { @@ -89,12 +89,12 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { try { - return $this->reserve($tokens, 0)->getLimit(); + return $this->reserve($tokens, 0)->getRateLimit(); } catch (MaxWaitDurationExceededException $e) { - return $e->getLimit(); + return $e->getRateLimit(); } } diff --git a/src/Symfony/Component/RateLimiter/LimiterInterface.php b/src/Symfony/Component/RateLimiter/LimiterInterface.php index e04a7ea26b4f0..f190f56354e64 100644 --- a/src/Symfony/Component/RateLimiter/LimiterInterface.php +++ b/src/Symfony/Component/RateLimiter/LimiterInterface.php @@ -43,7 +43,7 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation; * * @param int $tokens the number of tokens required */ - public function consume(int $tokens = 1): Limit; + public function consume(int $tokens = 1): RateLimit; /** * Resets the limit. diff --git a/src/Symfony/Component/RateLimiter/NoLimiter.php b/src/Symfony/Component/RateLimiter/NoLimiter.php index 65f772a66efe1..13ccbf10b6c0e 100644 --- a/src/Symfony/Component/RateLimiter/NoLimiter.php +++ b/src/Symfony/Component/RateLimiter/NoLimiter.php @@ -25,12 +25,12 @@ final class NoLimiter implements LimiterInterface { public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation { - return new Reservation(time(), new Limit(\INF, new \DateTimeImmutable(), true)); + return new Reservation(time(), new RateLimit(\INF, new \DateTimeImmutable(), true, \INF)); } - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { - return new Limit(\INF, new \DateTimeImmutable(), true); + return new RateLimit(\INF, new \DateTimeImmutable(), true, \INF); } public function reset(): void diff --git a/src/Symfony/Component/RateLimiter/Limit.php b/src/Symfony/Component/RateLimiter/RateLimit.php similarity index 87% rename from src/Symfony/Component/RateLimiter/Limit.php rename to src/Symfony/Component/RateLimiter/RateLimit.php index fb59ceb127cd4..64c706b6e6562 100644 --- a/src/Symfony/Component/RateLimiter/Limit.php +++ b/src/Symfony/Component/RateLimiter/RateLimit.php @@ -18,17 +18,19 @@ * * @experimental in 5.2 */ -class Limit +class RateLimit { private $availableTokens; private $retryAfter; private $accepted; + private $limit; - public function __construct(int $availableTokens, \DateTimeImmutable $retryAfter, bool $accepted) + public function __construct(int $availableTokens, \DateTimeImmutable $retryAfter, bool $accepted, int $limit) { $this->availableTokens = $availableTokens; $this->retryAfter = $retryAfter; $this->accepted = $accepted; + $this->limit = $limit; } public function isAccepted(): bool @@ -58,6 +60,11 @@ public function getRemainingTokens(): int return $this->availableTokens; } + public function getLimit(): int + { + return $this->limit; + } + public function wait(): void { sleep(($this->retryAfter->getTimestamp() - time()) * 1e6); diff --git a/src/Symfony/Component/RateLimiter/Reservation.php b/src/Symfony/Component/RateLimiter/Reservation.php index 26a1d1750d44d..4ea54ce5a8816 100644 --- a/src/Symfony/Component/RateLimiter/Reservation.php +++ b/src/Symfony/Component/RateLimiter/Reservation.php @@ -19,15 +19,15 @@ final class Reservation { private $timeToAct; - private $limit; + private $rateLimit; /** * @param float $timeToAct Unix timestamp in seconds when this reservation should act */ - public function __construct(float $timeToAct, Limit $limit) + public function __construct(float $timeToAct, RateLimit $rateLimit) { $this->timeToAct = $timeToAct; - $this->limit = $limit; + $this->rateLimit = $rateLimit; } public function getTimeToAct(): float @@ -40,9 +40,9 @@ public function getWaitDuration(): float return max(0, (-microtime(true)) + $this->timeToAct); } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } public function wait(): void diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php index dcdf6198439d2..4d89e89615fcb 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php @@ -76,7 +76,7 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { $this->lock->acquire(true); @@ -91,13 +91,13 @@ public function consume(int $tokens = 1): Limit $hitCount = $window->getHitCount(); $availableTokens = $this->getAvailableTokens($hitCount); if ($availableTokens < $tokens) { - return new Limit($availableTokens, $window->getRetryAfter(), false); + return new RateLimit($availableTokens, $window->getRetryAfter(), false, $this->limit); } $window->add($tokens); $this->storage->save($window); - return new Limit($this->getAvailableTokens($window->getHitCount()), $window->getRetryAfter(), true); + return new RateLimit($this->getAvailableTokens($window->getHitCount()), $window->getRetryAfter(), true, $this->limit); } finally { $this->lock->release(); } diff --git a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php index a6f436616f933..8ae6dcc875c24 100644 --- a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php @@ -41,10 +41,12 @@ public function testConsume() sleep(5); } - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $limit = $limiter->consume(); - $this->assertFalse($limit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertSame(10, $rateLimit->getLimit()); + $this->assertTrue($rateLimit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertFalse($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); } public function testConsumeOutsideInterval() @@ -58,18 +60,18 @@ public function testConsumeOutsideInterval() $limiter->consume(9); // ...try bursting again at the start of the next window sleep(10); - $limit = $limiter->consume(10); - $this->assertEquals(0, $limit->getRemainingTokens()); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(10); + $this->assertEquals(0, $rateLimit->getRemainingTokens()); + $this->assertTrue($rateLimit->isAccepted()); } public function testWrongWindowFromCache() { $this->storage->save(new DummyWindow()); $limiter = $this->createLimiter(); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(9, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(9, $rateLimit->getRemainingTokens()); } private function createLimiter(): FixedWindowLimiter diff --git a/src/Symfony/Component/RateLimiter/Tests/LimitTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php similarity index 67% rename from src/Symfony/Component/RateLimiter/Tests/LimitTest.php rename to src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php index a9865811146b6..c62eda36f4fd2 100644 --- a/src/Symfony/Component/RateLimiter/Tests/LimitTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php @@ -13,25 +13,25 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\RateLimiter\Exception\RateLimitExceededException; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; -class LimitTest extends TestCase +class RateLimitTest extends TestCase { public function testEnsureAcceptedDoesNotThrowExceptionIfAccepted() { - $limit = new Limit(10, new \DateTimeImmutable(), true); + $rateLimit = new RateLimit(10, new \DateTimeImmutable(), true, 10); - $this->assertSame($limit, $limit->ensureAccepted()); + $this->assertSame($rateLimit, $rateLimit->ensureAccepted()); } public function testEnsureAcceptedThrowsRateLimitExceptionIfNotAccepted() { - $limit = new Limit(10, $retryAfter = new \DateTimeImmutable(), false); + $rateLimit = new RateLimit(10, $retryAfter = new \DateTimeImmutable(), false, 10); try { - $limit->ensureAccepted(); + $rateLimit->ensureAccepted(); } catch (RateLimitExceededException $exception) { - $this->assertSame($limit, $exception->getLimit()); + $this->assertSame($rateLimit, $exception->getRateLimit()); $this->assertSame(10, $exception->getRemainingTokens()); $this->assertSame($retryAfter, $exception->getRetryAfter()); diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php index 341f216c29df4..07146c765d6d0 100644 --- a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php @@ -38,17 +38,19 @@ public function testConsume() $limiter->consume(8); sleep(15); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); // We are 25% into the new window - $limit = $limiter->consume(5); - $this->assertFalse($limit->isAccepted()); - $this->assertEquals(3, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(5); + $this->assertFalse($rateLimit->isAccepted()); + $this->assertEquals(3, $rateLimit->getRemainingTokens()); sleep(13); - $limit = $limiter->consume(10); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(10); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); } public function testReserve() diff --git a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php index 714ff15063087..b5b83649e20d9 100644 --- a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php @@ -74,26 +74,28 @@ public function testConsume() $limiter = $this->createLimiter(10, $rate); // enough free tokens - $limit = $limiter->consume(5); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(5, $limit->getRemainingTokens()); - $this->assertEqualsWithDelta(time(), $limit->getRetryAfter()->getTimestamp(), 1); + $rateLimit = $limiter->consume(5); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(5, $rateLimit->getRemainingTokens()); + $this->assertEqualsWithDelta(time(), $rateLimit->getRetryAfter()->getTimestamp(), 1); + $this->assertSame(10, $rateLimit->getLimit()); // there are only 5 available free tokens left now - $limit = $limiter->consume(10); - $this->assertEquals(5, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(10); + $this->assertEquals(5, $rateLimit->getRemainingTokens()); - $limit = $limiter->consume(5); - $this->assertEquals(0, $limit->getRemainingTokens()); - $this->assertEqualsWithDelta(time(), $limit->getRetryAfter()->getTimestamp(), 1); + $rateLimit = $limiter->consume(5); + $this->assertEquals(0, $rateLimit->getRemainingTokens()); + $this->assertEqualsWithDelta(time(), $rateLimit->getRetryAfter()->getTimestamp(), 1); + $this->assertSame(10, $rateLimit->getLimit()); } public function testWrongWindowFromCache() { $this->storage->save(new DummyWindow()); $limiter = $this->createLimiter(); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(9, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(9, $rateLimit->getRemainingTokens()); } private function createLimiter($initialTokens = 10, Rate $rate = null) diff --git a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php index b8997ac7e04a8..64b3046ec336d 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php @@ -74,16 +74,16 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation $bucket->setTokens($availableTokens - $tokens); $bucket->setTimer($now); - $reservation = new Reservation($now, new Limit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); + $reservation = new Reservation($now, new RateLimit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->maxBurst)); } else { $remainingTokens = $tokens - $availableTokens; $waitDuration = $this->rate->calculateTimeForTokens($remainingTokens); if (null !== $maxTime && $waitDuration > $maxTime) { // process needs to wait longer than set interval - $limit = new Limit($availableTokens, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false); + $rateLimit = new RateLimit($availableTokens, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst); - throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), $limit); + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), $rateLimit); } // at $now + $waitDuration all tokens will be reserved for this process, @@ -91,7 +91,7 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation $bucket->setTokens(0); $bucket->setTimer($now + $waitDuration); - $reservation = new Reservation($bucket->getTimer(), new Limit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + $reservation = new Reservation($bucket->getTimer(), new RateLimit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst)); } $this->storage->save($bucket); @@ -105,12 +105,12 @@ public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { try { - return $this->reserve($tokens, 0)->getLimit(); + return $this->reserve($tokens, 0)->getRateLimit(); } catch (MaxWaitDurationExceededException $e) { - return $e->getLimit(); + return $e->getRateLimit(); } } } From b3700bcfe609d1f2772ae6f5fd502e74f0a9b197 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Oct 2020 14:31:39 +0200 Subject: [PATCH 039/146] remove transport factory service when class does not exist --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 24cce5f9c31bc..e73820df7ed68 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -107,6 +107,7 @@ use Symfony\Component\Notifier\Bridge\FreeMobile\FreeMobileTransportFactory; use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory; use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory; +use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory; use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory; use Symfony\Component\Notifier\Bridge\Mobyt\MobytTransportFactory; use Symfony\Component\Notifier\Bridge\Nexmo\NexmoTransportFactory; @@ -2225,6 +2226,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ EsendexTransportFactory::class => 'notifier.transport_factory.esendex', SendinblueNotifierTransportFactory::class => 'notifier.transport_factory.sendinblue', DiscordTransportFactory::class => 'notifier.transport_factory.discord', + LinkedInTransportFactory::class => 'notifier.transport_factory.linkedin', ]; foreach ($classToServices as $class => $service) { From 143f82ef8e802c0f09622e09f58f5ff7508c1dd5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Oct 2020 14:40:03 +0200 Subject: [PATCH 040/146] forward the caught exception --- src/Symfony/Component/PropertyAccess/PropertyAccessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index cdf61947f4552..c0fb4d7beed37 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -115,7 +115,7 @@ public function setValue(&$objectOrArray, $propertyPath, $value) return; } catch (\TypeError $e) { - self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0, $propertyPath); + self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0, $propertyPath, $e); // It wasn't thrown in this class so rethrow it throw $e; } From 3f320c8d5168466ac12d66923df7d21ff0a16e76 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Tue, 20 Oct 2020 14:41:53 +0200 Subject: [PATCH 041/146] Refractor AbstractBrowserTest to assertSame --- .../BrowserKit/Tests/AbstractBrowserTest.php | 184 +++++++++--------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php index 25e76cb80168f..ca3d18a9536b5 100644 --- a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php @@ -68,7 +68,7 @@ public function testXmlHttpRequest() { $client = $this->getBrowser(); $client->xmlHttpRequest('GET', 'http://example.com/', [], [], [], null, true); - $this->assertEquals($client->getRequest()->getServer()['HTTP_X_REQUESTED_WITH'], 'XMLHttpRequest'); + $this->assertSame('XMLHttpRequest', $client->getRequest()->getServer()['HTTP_X_REQUESTED_WITH']); $this->assertFalse($client->getServerParameter('HTTP_X_REQUESTED_WITH', false)); } @@ -77,9 +77,9 @@ public function testGetRequestWithIpAsHttpHost() $client = $this->getBrowser(); $client->request('GET', 'https://example.com/foo', [], [], ['HTTP_HOST' => '127.0.0.1']); - $this->assertEquals('https://example.com/foo', $client->getRequest()->getUri()); + $this->assertSame('https://example.com/foo', $client->getRequest()->getUri()); $headers = $client->getRequest()->getServer(); - $this->assertEquals('127.0.0.1', $headers['HTTP_HOST']); + $this->assertSame('127.0.0.1', $headers['HTTP_HOST']); } public function testGetResponse() @@ -88,7 +88,7 @@ public function testGetResponse() $client->setNextResponse(new Response('foo')); $client->request('GET', 'http://example.com/'); - $this->assertEquals('foo', $client->getResponse()->getContent(), '->getCrawler() returns the Response of the last request'); + $this->assertSame('foo', $client->getResponse()->getContent(), '->getCrawler() returns the Response of the last request'); $this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getResponse(), '->getCrawler() returns the Response of the last request'); } @@ -118,7 +118,7 @@ public function testGetContent() $client = $this->getBrowser(); $client->request('POST', 'http://example.com/jsonrpc', [], [], [], $json); - $this->assertEquals($json, $client->getRequest()->getContent()); + $this->assertSame($json, $client->getRequest()->getContent()); } public function testGetCrawler() @@ -145,12 +145,12 @@ public function testRequestHttpHeaders() $client = $this->getBrowser(); $client->request('GET', '/'); $headers = $client->getRequest()->getServer(); - $this->assertEquals('localhost', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); + $this->assertSame('localhost', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); $headers = $client->getRequest()->getServer(); - $this->assertEquals('www.example.com', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); + $this->assertSame('www.example.com', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); $client->request('GET', 'https://www.example.com'); $headers = $client->getRequest()->getServer(); @@ -159,66 +159,66 @@ public function testRequestHttpHeaders() $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com:8080'); $headers = $client->getRequest()->getServer(); - $this->assertEquals('www.example.com:8080', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header with port'); + $this->assertSame('www.example.com:8080', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header with port'); } public function testRequestURIConversion() { $client = $this->getBrowser(); $client->request('GET', '/foo'); - $this->assertEquals('http://localhost/foo', $client->getRequest()->getUri(), '->request() converts the URI to an absolute one'); + $this->assertSame('http://localhost/foo', $client->getRequest()->getUri(), '->request() converts the URI to an absolute one'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); - $this->assertEquals('http://www.example.com', $client->getRequest()->getUri(), '->request() does not change absolute URIs'); + $this->assertSame('http://www.example.com', $client->getRequest()->getUri(), '->request() does not change absolute URIs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', '/foo'); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '#'); - $this->assertEquals('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); + $this->assertSame('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); $client->request('GET', '#'); - $this->assertEquals('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); + $this->assertSame('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); $client->request('GET', '#foo'); - $this->assertEquals('http://www.example.com/foo#foo', $client->getRequest()->getUri(), '->request() uses the previous request for #'); + $this->assertSame('http://www.example.com/foo#foo', $client->getRequest()->getUri(), '->request() uses the previous request for #'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'bar'); - $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); - $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'http'); - $this->assertEquals('http://www.example.com/foo/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/foo/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', 'http/bar'); - $this->assertEquals('http://www.example.com/http/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/http/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', 'http'); - $this->assertEquals('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + $this->assertSame('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '?'); - $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); + $this->assertSame('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); $client->request('GET', '?'); - $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); + $this->assertSame('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); $client->request('GET', '?foo=bar'); - $this->assertEquals('http://www.example.com/foo?foo=bar', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); + $this->assertSame('http://www.example.com/foo?foo=bar', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); } public function testRequestReferer() @@ -227,7 +227,7 @@ public function testRequestReferer() $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); $server = $client->getRequest()->getServer(); - $this->assertEquals('http://www.example.com/foo/foobar', $server['HTTP_REFERER'], '->request() sets the referer'); + $this->assertSame('http://www.example.com/foo/foobar', $server['HTTP_REFERER'], '->request() sets the referer'); } public function testRequestRefererCanBeOverridden() @@ -236,7 +236,7 @@ public function testRequestRefererCanBeOverridden() $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar', [], [], ['HTTP_REFERER' => 'xyz']); $server = $client->getRequest()->getServer(); - $this->assertEquals('xyz', $server['HTTP_REFERER'], '->request() allows referer to be overridden'); + $this->assertSame('xyz', $server['HTTP_REFERER'], '->request() allows referer to be overridden'); } public function testRequestHistory() @@ -245,8 +245,8 @@ public function testRequestHistory() $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); - $this->assertEquals('http://www.example.com/foo/bar', $client->getHistory()->current()->getUri(), '->request() updates the History'); - $this->assertEquals('http://www.example.com/foo/foobar', $client->getHistory()->back()->getUri(), '->request() updates the History'); + $this->assertSame('http://www.example.com/foo/bar', $client->getHistory()->current()->getUri(), '->request() updates the History'); + $this->assertSame('http://www.example.com/foo/foobar', $client->getHistory()->back()->getUri(), '->request() updates the History'); } public function testRequestCookies() @@ -254,10 +254,10 @@ public function testRequestCookies() $client = $this->getBrowser(); $client->setNextResponse(new Response('foo', 200, ['Set-Cookie' => 'foo=bar'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); + $this->assertSame(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); $client->request('GET', 'bar'); - $this->assertEquals(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); + $this->assertSame(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); } public function testRequestSecureCookies() @@ -277,7 +277,7 @@ public function testClick() $client->click($crawler->filter('a')->link()); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() clicks on links'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() clicks on links'); } public function testClickLink() @@ -287,7 +287,7 @@ public function testClickLink() $client->request('GET', 'http://www.example.com/foo/foobar'); $client->clickLink('foo'); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() clicks on links'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() clicks on links'); } public function testClickLinkNotFound() @@ -312,7 +312,7 @@ public function testClickForm() $client->click($crawler->filter('input')->form()); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() Form submit forms'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->click() Form submit forms'); } public function testSubmit() @@ -323,7 +323,7 @@ public function testSubmit() $client->submit($crawler->filter('input')->form()); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms'); } public function testSubmitForm() @@ -339,11 +339,11 @@ public function testSubmitForm() 'HTTP_USER_AGENT' => 'Symfony User Agent', ]); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->submitForm() submit forms'); - $this->assertEquals('PUT', $client->getRequest()->getMethod(), '->submitForm() allows to change the method'); - $this->assertEquals('new username', $client->getRequest()->getParameters()['username'], '->submitForm() allows to override the form values'); - $this->assertEquals('new password', $client->getRequest()->getParameters()['password'], '->submitForm() allows to override the form values'); - $this->assertEquals('Symfony User Agent', $client->getRequest()->getServer()['HTTP_USER_AGENT'], '->submitForm() allows to change the $_SERVER parameters'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->submitForm() submit forms'); + $this->assertSame('PUT', $client->getRequest()->getMethod(), '->submitForm() allows to change the method'); + $this->assertSame('new username', $client->getRequest()->getParameters()['username'], '->submitForm() allows to override the form values'); + $this->assertSame('new password', $client->getRequest()->getParameters()['password'], '->submitForm() allows to override the form values'); + $this->assertSame('Symfony User Agent', $client->getRequest()->getServer()['HTTP_USER_AGENT'], '->submitForm() allows to change the $_SERVER parameters'); } public function testSubmitFormNotFound() @@ -371,19 +371,19 @@ public function testSubmitPreserveAuth() $server = $client->getRequest()->getServer(); $this->assertArrayHasKey('PHP_AUTH_USER', $server); - $this->assertEquals('foo', $server['PHP_AUTH_USER']); + $this->assertSame('foo', $server['PHP_AUTH_USER']); $this->assertArrayHasKey('PHP_AUTH_PW', $server); - $this->assertEquals('bar', $server['PHP_AUTH_PW']); + $this->assertSame('bar', $server['PHP_AUTH_PW']); $client->submit($crawler->filter('input')->form()); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms'); $server = $client->getRequest()->getServer(); $this->assertArrayHasKey('PHP_AUTH_USER', $server); - $this->assertEquals('foo', $server['PHP_AUTH_USER']); + $this->assertSame('foo', $server['PHP_AUTH_USER']); $this->assertArrayHasKey('PHP_AUTH_PW', $server); - $this->assertEquals('bar', $server['PHP_AUTH_PW']); + $this->assertSame('bar', $server['PHP_AUTH_PW']); } public function testSubmitPassthrewHeaders() @@ -397,7 +397,7 @@ public function testSubmitPassthrewHeaders() $server = $client->getRequest()->getServer(); $this->assertArrayHasKey('Accept-Language', $server); - $this->assertEquals('de', $server['Accept-Language']); + $this->assertSame('de', $server['Accept-Language']); } public function testFollowRedirect() @@ -417,19 +417,19 @@ public function testFollowRedirect() $client->request('GET', 'http://www.example.com/foo/foobar'); $client->followRedirect(); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() automatically follows redirects if followRedirects is true'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() automatically follows redirects if followRedirects is true'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->followRedirect() does not follow redirect if HTTP Code is not 30x'); + $this->assertSame('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->followRedirect() does not follow redirect if HTTP Code is not 30x'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); @@ -449,12 +449,12 @@ public function testFollowRelativeRedirect() $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected:1234'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected:1234', $client->getRequest()->getUri(), '->followRedirect() follows relative urls'); + $this->assertSame('http://www.example.com/redirected:1234', $client->getRequest()->getUri(), '->followRedirect() follows relative urls'); } public function testFollowRedirectWithMaxRedirects() @@ -463,7 +463,7 @@ public function testFollowRedirectWithMaxRedirects() $client->setMaxRedirects(1); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected2'])); try { @@ -475,25 +475,25 @@ public function testFollowRedirectWithMaxRedirects() $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows relative URLs'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows relative URLs'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '//www.example.org/'])); $client->request('GET', 'https://www.example.com/'); - $this->assertEquals('https://www.example.org/', $client->getRequest()->getUri(), '->followRedirect() follows protocol-relative URLs'); + $this->assertSame('https://www.example.org/', $client->getRequest()->getUri(), '->followRedirect() follows protocol-relative URLs'); $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', ['name' => 'bar']); - $this->assertEquals('GET', $client->getRequest()->getMethod(), '->followRedirect() uses a GET for 302'); - $this->assertEquals([], $client->getRequest()->getParameters(), '->followRedirect() does not submit parameters when changing the method'); + $this->assertSame('GET', $client->getRequest()->getMethod(), '->followRedirect() uses a GET for 302'); + $this->assertSame([], $client->getRequest()->getParameters(), '->followRedirect() does not submit parameters when changing the method'); } public function testFollowRedirectWithCookies() @@ -505,9 +505,9 @@ public function testFollowRedirectWithCookies() 'Set-Cookie' => 'foo=bar', ])); $client->request('GET', 'http://www.example.com/'); - $this->assertEquals([], $client->getRequest()->getCookies()); + $this->assertSame([], $client->getRequest()->getCookies()); $client->followRedirect(); - $this->assertEquals(['foo' => 'bar'], $client->getRequest()->getCookies()); + $this->assertSame(['foo' => 'bar'], $client->getRequest()->getCookies()); } public function testFollowRedirectWithHeaders() @@ -566,9 +566,9 @@ public function testIsFollowingRedirects() public function testGetMaxRedirects() { $client = $this->getBrowser(); - $this->assertEquals(-1, $client->getMaxRedirects(), '->getMaxRedirects() returns default value'); + $this->assertSame(-1, $client->getMaxRedirects(), '->getMaxRedirects() returns default value'); $client->setMaxRedirects(3); - $this->assertEquals(3, $client->getMaxRedirects(), '->getMaxRedirects() returns assigned value'); + $this->assertSame(3, $client->getMaxRedirects(), '->getMaxRedirects() returns assigned value'); } public function testFollowRedirectWithPostMethod() @@ -583,12 +583,12 @@ public function testFollowRedirectWithPostMethod() $client->setNextResponse(new Response('', 307, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect with POST method'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect with POST method'); $this->assertArrayHasKey('foo', $client->getRequest()->getParameters(), '->followRedirect() keeps parameters with POST method'); $this->assertArrayHasKey('myfile.foo', $client->getRequest()->getFiles(), '->followRedirect() keeps files with POST method'); $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->followRedirect() keeps $_SERVER with POST method'); - $this->assertEquals($content, $client->getRequest()->getContent(), '->followRedirect() keeps content with POST method'); - $this->assertEquals('POST', $client->getRequest()->getMethod(), '->followRedirect() keeps request method'); + $this->assertSame($content, $client->getRequest()->getContent(), '->followRedirect() keeps content with POST method'); + $this->assertSame('POST', $client->getRequest()->getMethod(), '->followRedirect() keeps request method'); } public function testFollowRedirectDropPostMethod() @@ -604,12 +604,12 @@ public function testFollowRedirectDropPostMethod() $client->setNextResponse(new Response('', $code, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect with POST method on response code: '.$code.'.'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect with POST method on response code: '.$code.'.'); $this->assertEmpty($client->getRequest()->getParameters(), '->followRedirect() drops parameters with POST method on response code: '.$code.'.'); $this->assertEmpty($client->getRequest()->getFiles(), '->followRedirect() drops files with POST method on response code: '.$code.'.'); $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->followRedirect() keeps $_SERVER with POST method on response code: '.$code.'.'); $this->assertEmpty($client->getRequest()->getContent(), '->followRedirect() drops content with POST method on response code: '.$code.'.'); - $this->assertEquals('GET', $client->getRequest()->getMethod(), '->followRedirect() drops request method to GET on response code: '.$code.'.'); + $this->assertSame('GET', $client->getRequest()->getMethod(), '->followRedirect() drops request method to GET on response code: '.$code.'.'); } } @@ -622,7 +622,7 @@ public function testFollowMetaRefresh(string $content, string $expectedEndingUrl $client->followMetaRefresh($followMetaRefresh); $client->setNextResponse(new Response($content)); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals($expectedEndingUrl, $client->getRequest()->getUri()); + $this->assertSame($expectedEndingUrl, $client->getRequest()->getUri()); } public function getTestsForMetaRefresh() @@ -659,11 +659,11 @@ public function testBack() $client->request('GET', 'http://www.example.com/foo'); $client->back(); - $this->assertEquals('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->back() goes back in the history'); + $this->assertSame('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->back() goes back in the history'); $this->assertArrayHasKey('foo', $client->getRequest()->getParameters(), '->back() keeps parameters'); $this->assertArrayHasKey('myfile.foo', $client->getRequest()->getFiles(), '->back() keeps files'); $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->back() keeps $_SERVER'); - $this->assertEquals($content, $client->getRequest()->getContent(), '->back() keeps content'); + $this->assertSame($content, $client->getRequest()->getContent(), '->back() keeps content'); } public function testForward() @@ -680,11 +680,11 @@ public function testForward() $client->back(); $client->forward(); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->forward() goes forward in the history'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->forward() goes forward in the history'); $this->assertArrayHasKey('foo', $client->getRequest()->getParameters(), '->forward() keeps parameters'); $this->assertArrayHasKey('myfile.foo', $client->getRequest()->getFiles(), '->forward() keeps files'); $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->forward() keeps $_SERVER'); - $this->assertEquals($content, $client->getRequest()->getContent(), '->forward() keeps content'); + $this->assertSame($content, $client->getRequest()->getContent(), '->forward() keeps content'); } public function testBackAndFrowardWithRedirects() @@ -695,15 +695,15 @@ public function testBackAndFrowardWithRedirects() $client->setNextResponse(new Response('', 301, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/bar'); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), 'client followed redirect'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), 'client followed redirect'); $client->back(); - $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->back() goes back in the history skipping redirects'); + $this->assertSame('http://www.example.com/foo', $client->getRequest()->getUri(), '->back() goes back in the history skipping redirects'); $client->forward(); - $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->forward() goes forward in the history skipping redirects'); + $this->assertSame('http://www.example.com/redirected', $client->getRequest()->getUri(), '->forward() goes forward in the history skipping redirects'); } public function testReload() @@ -718,11 +718,11 @@ public function testReload() $client->request('GET', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); $client->reload(); - $this->assertEquals('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->reload() reloads the current page'); + $this->assertSame('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->reload() reloads the current page'); $this->assertArrayHasKey('foo', $client->getRequest()->getParameters(), '->reload() keeps parameters'); $this->assertArrayHasKey('myfile.foo', $client->getRequest()->getFiles(), '->reload() keeps files'); $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->reload() keeps $_SERVER'); - $this->assertEquals($content, $client->getRequest()->getContent(), '->reload() keeps content'); + $this->assertSame($content, $client->getRequest()->getContent(), '->reload() keeps content'); } public function testRestart() @@ -732,7 +732,7 @@ public function testRestart() $client->restart(); $this->assertTrue($client->getHistory()->isEmpty(), '->restart() clears the history'); - $this->assertEquals([], $client->getCookieJar()->all(), '->restart() clears the cookies'); + $this->assertSame([], $client->getCookieJar()->all(), '->restart() clears the cookies'); } /** @@ -745,7 +745,7 @@ public function testInsulatedRequests() $client->setNextScript("new Symfony\Component\BrowserKit\Response('foobar')"); $client->request('GET', 'http://www.example.com/foo/foobar'); - $this->assertEquals('foobar', $client->getResponse()->getContent(), '->insulate() process the request in a forked process'); + $this->assertSame('foobar', $client->getResponse()->getContent(), '->insulate() process the request in a forked process'); $client->setNextScript("new Symfony\Component\BrowserKit\Response('foobar)"); @@ -760,31 +760,31 @@ public function testInsulatedRequests() public function testGetServerParameter() { $client = $this->getBrowser(); - $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); - $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); - $this->assertEquals('testvalue', $client->getServerParameter('testkey', 'testvalue')); + $this->assertSame('', $client->getServerParameter('HTTP_HOST')); + $this->assertSame('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); + $this->assertSame('testvalue', $client->getServerParameter('testkey', 'testvalue')); } public function testSetServerParameter() { $client = $this->getBrowser(); - $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); - $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); + $this->assertSame('', $client->getServerParameter('HTTP_HOST')); + $this->assertSame('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $client->setServerParameter('HTTP_HOST', 'testhost'); - $this->assertEquals('testhost', $client->getServerParameter('HTTP_HOST')); + $this->assertSame('testhost', $client->getServerParameter('HTTP_HOST')); $client->setServerParameter('HTTP_USER_AGENT', 'testua'); - $this->assertEquals('testua', $client->getServerParameter('HTTP_USER_AGENT')); + $this->assertSame('testua', $client->getServerParameter('HTTP_USER_AGENT')); } public function testSetServerParameterInRequest() { $client = $this->getBrowser(); - $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); - $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); + $this->assertSame('', $client->getServerParameter('HTTP_HOST')); + $this->assertSame('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $client->request('GET', 'https://www.example.com/https/www.example.com', [], [], [ 'HTTP_HOST' => 'testhost', @@ -793,21 +793,21 @@ public function testSetServerParameterInRequest() 'NEW_SERVER_KEY' => 'new-server-key-value', ]); - $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); - $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); + $this->assertSame('', $client->getServerParameter('HTTP_HOST')); + $this->assertSame('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); - $this->assertEquals('https://www.example.com/https/www.example.com', $client->getRequest()->getUri()); + $this->assertSame('https://www.example.com/https/www.example.com', $client->getRequest()->getUri()); $server = $client->getRequest()->getServer(); $this->assertArrayHasKey('HTTP_USER_AGENT', $server); - $this->assertEquals('testua', $server['HTTP_USER_AGENT']); + $this->assertSame('testua', $server['HTTP_USER_AGENT']); $this->assertArrayHasKey('HTTP_HOST', $server); - $this->assertEquals('testhost', $server['HTTP_HOST']); + $this->assertSame('testhost', $server['HTTP_HOST']); $this->assertArrayHasKey('NEW_SERVER_KEY', $server); - $this->assertEquals('new-server-key-value', $server['NEW_SERVER_KEY']); + $this->assertSame('new-server-key-value', $server['NEW_SERVER_KEY']); $this->assertArrayHasKey('HTTPS', $server); $this->assertTrue($server['HTTPS']); @@ -821,13 +821,13 @@ public function testRequestWithRelativeUri() 'HTTP_HOST' => 'testhost', 'HTTPS' => true, ]); - $this->assertEquals('https://testhost/', $client->getRequest()->getUri()); + $this->assertSame('https://testhost/', $client->getRequest()->getUri()); $client->request('GET', 'https://www.example.com/', [], [], [ 'HTTP_HOST' => 'testhost', 'HTTPS' => false, ]); - $this->assertEquals('https://www.example.com/', $client->getRequest()->getUri()); + $this->assertSame('https://www.example.com/', $client->getRequest()->getUri()); } public function testInternalRequest() From fa265c2ee404aecc8914c2afbd64cad2a533e52b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Oct 2020 15:38:40 +0200 Subject: [PATCH 042/146] skip Vulcain-based tests if the binary cannot be executed --- .../Component/HttpClient/Tests/CurlHttpClientTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php index 6793818d55008..269705a3f4b9b 100644 --- a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php @@ -169,6 +169,14 @@ private function getVulcainClient(): CurlHttpClient sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1); if (!$process->isRunning()) { + if ('\\' !== \DIRECTORY_SEPARATOR && 127 === $process->getExitCode()) { + $this->markTestSkipped('vulcain binary is missing'); + } + + if ('\\' !== \DIRECTORY_SEPARATOR && 126 === $process->getExitCode()) { + $this->markTestSkipped('vulcain binary is not executable'); + } + throw new ProcessFailedException($process); } From 53434c2becac0aef61c5f7265834c0fb0582ea61 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Oct 2020 15:07:20 +0200 Subject: [PATCH 043/146] fix APCu installation for the nightly build job --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 254d3c600e3f5..648e955995da8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -157,15 +157,14 @@ before_install: fi if [[ $PHP = nightly ]]; then tfold ext.memcached tpecl memcached-3.1.5 memcached.so $INI - tfold ext.apcu install_apcu_dev 9c36db45100d4d27ec33072f4be90f1f5a0108b7 $INI else - tfold ext.apcu tpecl apcu-5.1.19 apcu.so $INI tfold ext.mongodb tpecl mongodb-1.6.16 mongodb.so $INI tfold ext.zookeeper tpecl zookeeper-0.7.2 zookeeper.so $INI tfold ext.amqp tpecl amqp-1.10.2 amqp.so $INI tfold ext.redis tpecl redis-5.2.2 redis.so $INI "no" fi + tfold ext.apcu tpecl apcu-5.1.19 apcu.so $INI tfold ext.igbinary tpecl igbinary-3.1.6 igbinary.so $INI done - | From 1cde6ca03fcef0e9087131deb5631fe16ca5fac3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 20 Oct 2020 23:27:26 +0200 Subject: [PATCH 044/146] [Filesystem] Check if failed unlink was caused by permission denied --- .../Component/Filesystem/Filesystem.php | 2 +- .../Filesystem/Tests/FilesystemTest.php | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index a6e8715256be6..96b2e96009f43 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -179,7 +179,7 @@ public function remove($files) if (!self::box('rmdir', $file) && file_exists($file)) { throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError); } - } elseif (!self::box('unlink', $file) && file_exists($file)) { + } elseif (!self::box('unlink', $file) && (false !== strpos(self::$lastError, 'Permission denied') || file_exists($file))) { throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError); } } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 14837152b3a10..b157cc4ed3e74 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Filesystem\Tests; +use Symfony\Component\Filesystem\Exception\IOException; + /** * Test class for Filesystem. */ @@ -334,6 +336,28 @@ public function testRemoveIgnoresNonExistingFiles() $this->assertFileDoesNotExist($basePath.'dir'); } + public function testRemoveThrowsExceptionOnPermissionDenied() + { + $this->markAsSkippedIfChmodIsMissing(); + + $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'dir_permissions'; + mkdir($basePath); + $file = $basePath.\DIRECTORY_SEPARATOR.'file'; + touch($file); + chmod($basePath, 0400); + + try { + $this->filesystem->remove($file); + $this->fail('Filesystem::remove() should throw an exception'); + } catch (IOException $e) { + $this->assertStringContainsString('Failed to remove file "'.$file.'"', $e->getMessage()); + $this->assertStringContainsString('Permission denied', $e->getMessage()); + } finally { + // Make sure we can clean up this file + chmod($basePath, 0777); + } + } + public function testRemoveCleansInvalidLinks() { $this->markAsSkippedIfSymlinkIsMissing(); From 5e7d3ab17b10f8bb8cdf23c4259ce8e28f048b01 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 20 Oct 2020 22:44:15 +0200 Subject: [PATCH 045/146] Enabled to use the UniqueEntity constraint as an attribute. --- .../Constraints/UniqueEntityTest.php | 85 +++++++++++ .../Constraints/UniqueEntityValidatorTest.php | 140 +++++++++++------- .../Validator/Constraints/UniqueEntity.php | 36 +++++ src/Symfony/Bridge/Doctrine/composer.json | 4 +- 4 files changed, 212 insertions(+), 53 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php new file mode 100644 index 0000000000000..bd9791bc65a96 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Validator\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; + +/** + * @requires PHP 8 + */ +class UniqueEntityTest extends TestCase +{ + public function testAttributeWithDefaultProperty() + { + $metadata = new ClassMetadata(UniqueEntityDummyOne::class); + $loader = new AnnotationLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + /** @var UniqueEntity $constraint */ + list($constraint) = $metadata->getConstraints(); + self::assertSame(['email'], $constraint->fields); + self::assertTrue($constraint->ignoreNull); + self::assertSame('doctrine.orm.validator.unique', $constraint->validatedBy()); + self::assertSame(['Default', 'UniqueEntityDummyOne'], $constraint->groups); + } + + public function testAttributeWithCustomizedService() + { + $metadata = new ClassMetadata(UniqueEntityDummyTwo::class); + $loader = new AnnotationLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + /** @var UniqueEntity $constraint */ + list($constraint) = $metadata->getConstraints(); + self::assertSame(['isbn'], $constraint->fields); + self::assertSame('my_own_validator', $constraint->validatedBy()); + self::assertSame('my_own_entity_manager', $constraint->em); + self::assertSame('App\Entity\MyEntity', $constraint->entityClass); + self::assertSame('fetchDifferently', $constraint->repositoryMethod); + } + + public function testAttributeWithGroupsAndPaylod() + { + $metadata = new ClassMetadata(UniqueEntityDummyThree::class); + $loader = new AnnotationLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + /** @var UniqueEntity $constraint */ + list($constraint) = $metadata->getConstraints(); + self::assertSame('uuid', $constraint->fields); + self::assertSame('id', $constraint->errorPath); + self::assertSame('some attached data', $constraint->payload); + self::assertSame(['some_group'], $constraint->groups); + } +} + +#[UniqueEntity(['email'], message: 'myMessage')] +class UniqueEntityDummyOne +{ + private $email; +} + +#[UniqueEntity(fields: ['isbn'], service: 'my_own_validator', em: 'my_own_entity_manager', entityClass: 'App\Entity\MyEntity', repositoryMethod: 'fetchDifferently')] +class UniqueEntityDummyTwo +{ + private $isbn; +} + +#[UniqueEntity('uuid', ignoreNull: false, errorPath: 'id', payload: 'some attached data', groups: ['some_group'])] +class UniqueEntityDummyThree +{ + private $id; + private $uuid; +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index e9e905c89c3a4..8507df94bf11c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -162,15 +162,11 @@ private function createSchema($em) /** * This is a functional test as there is a large integration necessary to get the validator working. + * + * @dataProvider provideUniquenessConstraints */ - public function testValidateUniqueness() + public function testValidateUniqueness(UniqueEntity $constraint) { - $constraint = new UniqueEntity([ - 'message' => 'myMessage', - 'fields' => ['name'], - 'em' => self::EM_NAME, - ]); - $entity1 = new SingleIntIdEntity(1, 'Foo'); $entity2 = new SingleIntIdEntity(2, 'Foo'); @@ -196,15 +192,24 @@ public function testValidateUniqueness() ->assertRaised(); } - public function testValidateCustomErrorPath() + public function provideUniquenessConstraints(): iterable { - $constraint = new UniqueEntity([ + yield 'Doctrine style' => [new UniqueEntity([ 'message' => 'myMessage', 'fields' => ['name'], 'em' => self::EM_NAME, - 'errorPath' => 'bar', - ]); + ])]; + + if (\PHP_VERSION_ID >= 80000) { + yield 'Named arguments' => [eval('return new \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity(message: "myMessage", fields: ["name"], em: "foo");')]; + } + } + /** + * @dataProvider provideConstraintsWithCustomErrorPath + */ + public function testValidateCustomErrorPath(UniqueEntity $constraint) + { $entity1 = new SingleIntIdEntity(1, 'Foo'); $entity2 = new SingleIntIdEntity(2, 'Foo'); @@ -222,14 +227,25 @@ public function testValidateCustomErrorPath() ->assertRaised(); } - public function testValidateUniquenessWithNull() + public function provideConstraintsWithCustomErrorPath(): iterable { - $constraint = new UniqueEntity([ + yield 'Doctrine style' => [new UniqueEntity([ 'message' => 'myMessage', 'fields' => ['name'], 'em' => self::EM_NAME, - ]); + 'errorPath' => 'bar', + ])]; + if (\PHP_VERSION_ID >= 80000) { + yield 'Named arguments' => [eval('return new \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity(message: "myMessage", fields: ["name"], em: "foo", errorPath: "bar");')]; + } + } + + /** + * @dataProvider provideUniquenessConstraints + */ + public function testValidateUniquenessWithNull(UniqueEntity $constraint) + { $entity1 = new SingleIntIdEntity(1, null); $entity2 = new SingleIntIdEntity(2, null); @@ -242,15 +258,11 @@ public function testValidateUniquenessWithNull() $this->assertNoViolation(); } - public function testValidateUniquenessWithIgnoreNullDisabled() + /** + * @dataProvider provideConstraintsWithIgnoreNullDisabled + */ + public function testValidateUniquenessWithIgnoreNullDisabled(UniqueEntity $constraint) { - $constraint = new UniqueEntity([ - 'message' => 'myMessage', - 'fields' => ['name', 'name2'], - 'em' => self::EM_NAME, - 'ignoreNull' => false, - ]); - $entity1 = new DoubleNameEntity(1, 'Foo', null); $entity2 = new DoubleNameEntity(2, 'Foo', null); @@ -276,30 +288,36 @@ public function testValidateUniquenessWithIgnoreNullDisabled() ->assertRaised(); } - public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgnoreNullEnabled() + public function provideConstraintsWithIgnoreNullDisabled(): iterable { - $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); - $constraint = new UniqueEntity([ + yield 'Doctrine style' => [new UniqueEntity([ 'message' => 'myMessage', 'fields' => ['name', 'name2'], 'em' => self::EM_NAME, - 'ignoreNull' => true, - ]); + 'ignoreNull' => false, + ])]; + if (\PHP_VERSION_ID >= 80000) { + yield 'Named arguments' => [eval('return new \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity(message: "myMessage", fields: ["name", "name2"], em: "foo", ignoreNull: false);')]; + } + } + + /** + * @dataProvider provideConstraintsWithIgnoreNullEnabled + */ + public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgnoreNullEnabled(UniqueEntity $constraint) + { $entity1 = new SingleIntIdEntity(1, null); + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); $this->validator->validate($entity1, $constraint); } - public function testNoValidationIfFirstFieldIsNullAndNullValuesAreIgnored() + /** + * @dataProvider provideConstraintsWithIgnoreNullEnabled + */ + public function testNoValidationIfFirstFieldIsNullAndNullValuesAreIgnored(UniqueEntity $constraint) { - $constraint = new UniqueEntity([ - 'message' => 'myMessage', - 'fields' => ['name', 'name2'], - 'em' => self::EM_NAME, - 'ignoreNull' => true, - ]); - $entity1 = new DoubleNullableNameEntity(1, null, 'Foo'); $entity2 = new DoubleNullableNameEntity(2, null, 'Foo'); @@ -319,6 +337,20 @@ public function testNoValidationIfFirstFieldIsNullAndNullValuesAreIgnored() $this->assertNoViolation(); } + public function provideConstraintsWithIgnoreNullEnabled(): iterable + { + yield 'Doctrine style' => [new UniqueEntity([ + 'message' => 'myMessage', + 'fields' => ['name', 'name2'], + 'em' => self::EM_NAME, + 'ignoreNull' => true, + ])]; + + if (\PHP_VERSION_ID >= 80000) { + yield 'Named arguments' => [eval('return new \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity(message: "myMessage", fields: ["name", "name2"], em: "foo", ignoreNull: true);')]; + } + } + public function testValidateUniquenessWithValidCustomErrorPath() { $constraint = new UniqueEntity([ @@ -353,15 +385,11 @@ public function testValidateUniquenessWithValidCustomErrorPath() ->assertRaised(); } - public function testValidateUniquenessUsingCustomRepositoryMethod() + /** + * @dataProvider provideConstraintsWithCustomRepositoryMethod + */ + public function testValidateUniquenessUsingCustomRepositoryMethod(UniqueEntity $constraint) { - $constraint = new UniqueEntity([ - 'message' => 'myMessage', - 'fields' => ['name'], - 'em' => self::EM_NAME, - 'repositoryMethod' => 'findByCustom', - ]); - $repository = $this->createRepositoryMock(); $repository->expects($this->once()) ->method('findByCustom') @@ -379,15 +407,11 @@ public function testValidateUniquenessUsingCustomRepositoryMethod() $this->assertNoViolation(); } - public function testValidateUniquenessWithUnrewoundArray() + /** + * @dataProvider provideConstraintsWithCustomRepositoryMethod + */ + public function testValidateUniquenessWithUnrewoundArray(UniqueEntity $constraint) { - $constraint = new UniqueEntity([ - 'message' => 'myMessage', - 'fields' => ['name'], - 'em' => self::EM_NAME, - 'repositoryMethod' => 'findByCustom', - ]); - $entity = new SingleIntIdEntity(1, 'foo'); $repository = $this->createRepositoryMock(); @@ -414,6 +438,20 @@ function () use ($entity) { $this->assertNoViolation(); } + public function provideConstraintsWithCustomRepositoryMethod(): iterable + { + yield 'Doctrine style' => [new UniqueEntity([ + 'message' => 'myMessage', + 'fields' => ['name'], + 'em' => self::EM_NAME, + 'repositoryMethod' => 'findByCustom', + ])]; + + if (\PHP_VERSION_ID >= 80000) { + yield 'Named arguments' => [eval('return new \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity(message: "myMessage", fields: ["name"], em: "foo", repositoryMethod: "findByCustom");')]; + } + } + /** * @dataProvider resultTypesProvider */ diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php index 2c319709ebc9d..168956da943c5 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php @@ -21,6 +21,7 @@ * * @author Benjamin Eberlei */ +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] class UniqueEntity extends Constraint { const NOT_UNIQUE_ERROR = '23bd9dbf-6b9b-41cd-a99e-4844bcf3077f'; @@ -38,6 +39,41 @@ class UniqueEntity extends Constraint self::NOT_UNIQUE_ERROR => 'NOT_UNIQUE_ERROR', ]; + /** + * {@inheritdoc} + * + * @param array|string $fields the combination of fields that must contain unique values or a set of options + */ + public function __construct( + $fields, + string $message = null, + string $service = null, + string $em = null, + string $entityClass = null, + string $repositoryMethod = null, + string $errorPath = null, + bool $ignoreNull = null, + array $groups = null, + $payload = null, + array $options = [] + ) { + if (\is_array($fields) && \is_string(key($fields))) { + $options = array_merge($fields, $options); + } elseif (null !== $fields) { + $options['fields'] = $fields; + } + + parent::__construct($options, $groups, $payload); + + $this->message = $message ?? $this->message; + $this->service = $service ?? $this->service; + $this->em = $em ?? $this->em; + $this->entityClass = $entityClass ?? $this->entityClass; + $this->repositoryMethod = $repositoryMethod ?? $this->repositoryMethod; + $this->errorPath = $errorPath ?? $this->errorPath; + $this->ignoreNull = $ignoreNull ?? $this->ignoreNull; + } + public function getRequiredOptions() { return ['fields']; diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 15c5b6294c534..0052cfa59cced 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -40,7 +40,7 @@ "symfony/security-core": "^5.0", "symfony/expression-language": "^4.4|^5.0", "symfony/uid": "^5.1", - "symfony/validator": "^5.0.2", + "symfony/validator": "^5.2", "symfony/translation": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0", "doctrine/annotations": "~1.7", @@ -61,7 +61,7 @@ "symfony/property-info": "<5", "symfony/security-bundle": "<5", "symfony/security-core": "<5", - "symfony/validator": "<5.0.2" + "symfony/validator": "<5.2" }, "suggest": { "symfony/form": "", From 17e016779867de45b342cacb31499bd6f81b01b5 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 19 Oct 2020 21:33:09 +0200 Subject: [PATCH 046/146] [Cache] Use correct expiry in ChainAdapter --- .../Component/Cache/Adapter/ChainAdapter.php | 4 +- .../Cache/Tests/Adapter/ChainAdapterTest.php | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php index 5973b3d562602..4c086c3d55c74 100644 --- a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php @@ -73,7 +73,9 @@ static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifeti $item->isHit = $sourceItem->isHit; $item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata; - if (0 < $defaultLifetime) { + if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) { + $item->expiresAt(\DateTime::createFromFormat('U.u', $item->metadata[CacheItem::METADATA_EXPIRY])); + } elseif (0 < $defaultLifetime) { $item->expiresAfter($defaultLifetime); } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php index 53295a1eef0e5..b2905297ebe7d 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -16,8 +16,10 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\ChainAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter; +use Symfony\Contracts\Cache\ItemInterface; /** * @author Kévin Dunglas @@ -34,6 +36,11 @@ public function createCachePool(int $defaultLifetime = 0, string $testMethod = n return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter($defaultLifetime), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime); } + public static function tearDownAfterClass(): void + { + FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); + } + public function testEmptyAdaptersException() { $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); @@ -187,6 +194,48 @@ public function testMultipleCachesExpirationWhenCommonTtlIsSet() $this->assertFalse($item->isHit()); } + public function testExpirationOnAllAdapters() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $itemValidator = function (CacheItem $item) { + $refl = new \ReflectionObject($item); + $propExpiry = $refl->getProperty('expiry'); + $propExpiry->setAccessible(true); + $expiry = $propExpiry->getValue($item); + $this->assertGreaterThan(10, $expiry - time(), 'Item should be saved with the given ttl, not the default for the adapter.'); + + return true; + }; + + $adapter1 = $this->getMockBuilder(FilesystemAdapter::class) + ->setConstructorArgs(['', 2]) + ->setMethods(['save']) + ->getMock(); + $adapter1->expects($this->once()) + ->method('save') + ->with($this->callback($itemValidator)) + ->willReturn(true); + + $adapter2 = $this->getMockBuilder(FilesystemAdapter::class) + ->setConstructorArgs(['', 4]) + ->setMethods(['save']) + ->getMock(); + $adapter2->expects($this->once()) + ->method('save') + ->with($this->callback($itemValidator)) + ->willReturn(true); + + $cache = new ChainAdapter([$adapter1, $adapter2], 6); + $cache->get('test_key', function (ItemInterface $item) { + $item->expiresAfter(15); + + return 'chain'; + }); + } + private function getPruneableMock(): AdapterInterface { $pruneable = $this->createMock(PrunableAdapter::class); From 6eb9d62bdd8002f8b3cb864ea2cd3e91fe59cb6b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Oct 2020 11:46:19 +0200 Subject: [PATCH 047/146] [HttpKernel] add `kernel.runtime_environment` = `%env(default:kernel.environment:APP_RUNTIME_ENV)%` parameter --- .../FrameworkBundle/DependencyInjection/Configuration.php | 2 +- .../Tests/DependencyInjection/ConfigurationTest.php | 2 +- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + src/Symfony/Component/HttpKernel/Kernel.php | 1 + src/Symfony/Component/HttpKernel/composer.json | 4 ++-- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0d4ee4f797528..e4ebe84243780 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -148,7 +148,7 @@ private function addSecretsSection(ArrayNodeDefinition $rootNode) ->arrayNode('secrets') ->canBeDisabled() ->children() - ->scalarNode('vault_directory')->defaultValue('%kernel.project_dir%/config/secrets/%kernel.environment%')->cannotBeEmpty()->end() + ->scalarNode('vault_directory')->defaultValue('%kernel.project_dir%/config/secrets/%kernel.runtime_environment%')->cannotBeEmpty()->end() ->scalarNode('local_dotenv_file')->defaultValue('%kernel.project_dir%/.env.%kernel.environment%.local')->end() ->scalarNode('decryption_env_var')->defaultValue('base64:default::SYMFONY_DECRYPTION_SECRET')->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 00afdfd00055f..6bc6d958b79b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -522,7 +522,7 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'error_controller' => 'error_controller', 'secrets' => [ 'enabled' => true, - 'vault_directory' => '%kernel.project_dir%/config/secrets/%kernel.environment%', + 'vault_directory' => '%kernel.project_dir%/config/secrets/%kernel.runtime_environment%', 'local_dotenv_file' => '%kernel.project_dir%/.env.%kernel.environment%.local', 'decryption_env_var' => 'base64:default::SYMFONY_DECRYPTION_SECRET', ], diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index a655e2d6f945a..364b8a67fc05f 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG in the request profiler raw content section * Allowed adding attributes on controller arguments that will be passed to argument resolvers. * kernels implementing the `ExtensionInterface` will now be auto-registered to the container + * added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%` 5.1.0 ----- diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index ad9a4b2d78a5b..c5a6be5344429 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -606,6 +606,7 @@ protected function getKernelParameters() return [ 'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(), 'kernel.environment' => $this->environment, + 'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%', 'kernel.debug' => $this->debug, 'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir, 'kernel.cache_dir' => realpath($this->getCacheDir()) ?: $this->getCacheDir(), diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 08dc362f9f6c5..1677de4bf5b23 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -32,7 +32,7 @@ "symfony/config": "^5.0", "symfony/console": "^4.4|^5.0", "symfony/css-selector": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", + "symfony/dependency-injection": "^5.1.8", "symfony/dom-crawler": "^4.4|^5.0", "symfony/expression-language": "^4.4|^5.0", "symfony/finder": "^4.4|^5.0", @@ -53,7 +53,7 @@ "symfony/config": "<5.0", "symfony/console": "<4.4", "symfony/form": "<5.0", - "symfony/dependency-injection": "<4.4", + "symfony/dependency-injection": "<5.1.8", "symfony/doctrine-bridge": "<5.0", "symfony/http-client": "<5.0", "symfony/mailer": "<5.0", From e325f51fe2b36829776a4be025f42df4c202b30c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 19 Oct 2020 18:27:34 +0200 Subject: [PATCH 048/146] [HttpClient] Fix decorating progress info in AsyncResponse --- .../FrameworkExtension.php | 2 +- .../DataCollector/HttpClientDataCollector.php | 6 ++++++ .../HttpClient/Response/AsyncContext.php | 6 ++++++ .../HttpClient/Response/AsyncResponse.php | 7 +++++++ .../HttpClient/RetryableHttpClient.php | 4 +--- .../Tests/AsyncDecoratorTraitTest.php | 19 +++++++++++++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 24cce5f9c31bc..e99bef78c5da8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2097,7 +2097,7 @@ private function registerRetryableHttpClient(array $options, string $name, Conta $container ->register($name.'.retryable', RetryableHttpClient::class) - ->setDecoratedService($name, null, -10) // lower priority than TraceableHttpClient + ->setDecoratedService($name, null, 10) // higher priority than TraceableHttpClient ->setArguments([new Reference($name.'.retryable.inner'), $retryStrategy, $options['max_retries'], new Reference('logger')]) ->addTag('monolog.logger', ['channel' => 'http_client']); } diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php index 7a60bdd435ac8..db8bbbdd69523 100644 --- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php +++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php @@ -98,6 +98,7 @@ private function collectOnClient(TraceableHttpClient $client): array $errorCount = 0; $baseInfo = [ 'response_headers' => 1, + 'retry_count' => 1, 'redirect_count' => 1, 'redirect_url' => 1, 'user_data' => 1, @@ -152,6 +153,11 @@ private function collectOnClient(TraceableHttpClient $client): array $content = []; } + if (isset($info['retry_count'])) { + $content['retries'] = $info['previous_info']; + unset($info['previous_info']); + } + $debugInfo = array_diff_key($info, $baseInfo); $info = ['info' => $debugInfo] + array_diff_key($info, $debugInfo) + $content; unset($traces[$i]['info']); // break PHP reference used by TraceableHttpClient diff --git a/src/Symfony/Component/HttpClient/Response/AsyncContext.php b/src/Symfony/Component/HttpClient/Response/AsyncContext.php index b0138968ffc19..ebadd1911a226 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncContext.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncContext.php @@ -151,6 +151,12 @@ public function getResponse(): ResponseInterface public function replaceRequest(string $method, string $url, array $options = []): ResponseInterface { $this->info['previous_info'][] = $this->response->getInfo(); + if (null !== $onProgress = $options['on_progress'] ?? null) { + $thisInfo = &$this->info; + $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) { + $onProgress($dlNow, $dlSize, $thisInfo + $info); + }; + } return $this->response = $this->client->request($method, $url, ['buffer' => false] + $options); } diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php index ab9dd6495fe69..0eb1355efda19 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php @@ -43,6 +43,13 @@ public function __construct(HttpClientInterface $client, string $method, string { $this->client = $client; $this->shouldBuffer = $options['buffer'] ?? true; + + if (null !== $onProgress = $options['on_progress'] ?? null) { + $thisInfo = &$this->info; + $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) { + $onProgress($dlNow, $dlSize, $thisInfo + $info); + }; + } $this->response = $client->request($method, $url, ['buffer' => false] + $options); $this->passthru = $passthru; $this->initializer = static function (self $response) { diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php index 6bca91e4f1dd3..387a33fc9b65c 100644 --- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php +++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php @@ -66,7 +66,6 @@ public function request(string $method, string $url, array $options = []): Respo } } catch (TransportExceptionInterface $exception) { // catch TransportExceptionInterface to send it to the strategy - $context->setInfo('retry_count', $retryCount); } if (null !== $exception) { // always retry request that fail to resolve DNS @@ -91,8 +90,6 @@ public function request(string $method, string $url, array $options = []): Respo } } } elseif ($chunk->isFirst()) { - $context->setInfo('retry_count', $retryCount); - if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) { $context->passthru(); yield $chunk; @@ -138,6 +135,7 @@ public function request(string $method, string $url, array $options = []): Respo 'delay' => $delay, ]); + $context->setInfo('retry_count', $retryCount); $context->replaceRequest($method, $url, $options); $context->pause($delay / 1000); diff --git a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php index 5bbe244600de0..90872ece7530d 100644 --- a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php @@ -263,4 +263,23 @@ public function request(string $method, string $url, array $options = []): Respo $this->assertSame('{"documents":[{"id":"\/json\/1"},{"id":"\/json\/2"},{"id":"\/json\/3"}]}', $content); } + + public function testInfoPassToDecorator() + { + $lastInfo = null; + $options = ['on_progress' => function (int $dlNow, int $dlSize, array $info) use (&$lastInfo) { + $lastInfo = $info; + }]; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use ($options) { + $context->setInfo('foo', 'test'); + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/', $options); + $context->passthru(); + }); + + $client->request('GET', 'http://localhost:8057')->getContent(); + $this->assertArrayHasKey('foo', $lastInfo); + $this->assertSame('test', $lastInfo['foo']); + $this->assertArrayHasKey('previous_info', $lastInfo); + } } From d31ac74c03ca9a538853f96396781002f04ac815 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 21 Oct 2020 15:57:03 +0200 Subject: [PATCH 049/146] [String] fix slicing in UnicodeString --- .../String/Tests/AbstractAsciiTestCase.php | 31 +++++++++++++++++++ .../Component/String/UnicodeString.php | 12 ++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 44f14c18af3a2..d752ea41eb608 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -597,6 +597,37 @@ public static function provideSlice() ['awesome', 'Symfony is awesome', 11, 7], ['awesome', 'Symfony is awesome', -7, null], ['awe', 'Symfony is awesome', -7, -4], + ['S', 'Symfony is awesome', -42, 1], + ['', 'Symfony is awesome', 42, 1], + ['', 'Symfony is awesome', 0, -42], + ]; + } + + /** + * @dataProvider provideSplice + */ + public function testSplice(string $expected, int $start, int $length = null) + { + $this->assertEquals( + static::createFromString($expected), + static::createFromString('Symfony is awesome')->splice('X', $start, $length) + ); + } + + public static function provideSplice() + { + return [ + ['X is awesome', 0, 7], + ['SymfonyXis awesome', 7, 1], + ['Symfony X awesome', 8, 2], + ['Symfony X', 8, null], + ['Symfony isXawesome', 10, 1], + ['Symfony is X', 11, 7], + ['Symfony is X', -7, null], + ['Symfony is Xsome', -7, -4], + ['Xymfony is awesome', -42, 1], + ['Symfony is awesomeX', 42, 1], + ['XSymfony is awesome', 0, -42], ]; } diff --git a/src/Symfony/Component/String/UnicodeString.php b/src/Symfony/Component/String/UnicodeString.php index 16945b70a4407..2db507d7bbf0e 100644 --- a/src/Symfony/Component/String/UnicodeString.php +++ b/src/Symfony/Component/String/UnicodeString.php @@ -267,11 +267,11 @@ public function replaceMatches(string $fromRegexp, $to): AbstractString public function slice(int $start = 0, int $length = null): AbstractString { $str = clone $this; - try { - $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647); - } catch (\ValueError $e) { - $str->string = ''; + + if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) { + $start = 0; } + $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647); return $str; } @@ -279,6 +279,10 @@ public function slice(int $start = 0, int $length = null): AbstractString public function splice(string $replacement, int $start = 0, int $length = null): AbstractString { $str = clone $this; + + if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) { + $start = 0; + } $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); From ccbf7d5a06f7e4d1260a9b9cb2c0ef8a16224b2c Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Oct 2020 23:43:19 +0200 Subject: [PATCH 050/146] [RateLimiter] Remove Window::sleep() --- src/Symfony/Component/RateLimiter/Window.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/Window.php b/src/Symfony/Component/RateLimiter/Window.php index 46ca1b38204b6..6a0934c05febe 100644 --- a/src/Symfony/Component/RateLimiter/Window.php +++ b/src/Symfony/Component/RateLimiter/Window.php @@ -85,12 +85,4 @@ public function calculateTimeForTokens(int $tokens): int return $cyclesRequired * $this->intervalInSeconds; } - - /** - * @internal - */ - public function __sleep(): array - { - return ['id', 'hitCount', 'intervalInSeconds', 'timer', 'maxSize']; - } } From 4795756cc7e2f4fe32daaea4fe912785d3e07405 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Oct 2020 23:51:48 +0200 Subject: [PATCH 051/146] [RateLimiter] Be more type safe when fetching form cache --- .../Component/RateLimiter/Storage/CacheStorage.php | 7 ++++--- .../RateLimiter/Tests/Storage/CacheStorageTest.php | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php b/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php index 5c39b0fcd2b2d..34e27798e6375 100644 --- a/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php +++ b/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php @@ -42,11 +42,12 @@ public function save(LimiterStateInterface $limiterState): void public function fetch(string $limiterStateId): ?LimiterStateInterface { $cacheItem = $this->pool->getItem(sha1($limiterStateId)); - if (!$cacheItem->isHit()) { - return null; + $value = $cacheItem->get(); + if ($value instanceof LimiterStateInterface) { + return $value; } - return $cacheItem->get(); + return null; } public function delete(string $limiterStateId): void diff --git a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php index de8f77b4630e8..97de6e554fda7 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php @@ -55,6 +55,18 @@ public function testFetchExistingState() $this->assertEquals($window, $this->storage->fetch('test')); } + public function testFetchExistingJunk() + { + $cacheItem = $this->createMock(CacheItemInterface::class); + + $cacheItem->expects($this->any())->method('get')->willReturn('junk'); + $cacheItem->expects($this->any())->method('isHit')->willReturn(true); + + $this->pool->expects($this->any())->method('getItem')->with(sha1('test'))->willReturn($cacheItem); + + $this->assertNull($this->storage->fetch('test')); + } + public function testFetchNonExistingState() { $cacheItem = $this->createMock(CacheItemInterface::class); From ced43e1ec20d26c11ad3ca96f239e21bcc8a80a4 Mon Sep 17 00:00:00 2001 From: Marcin Michalski Date: Thu, 22 Oct 2020 07:16:57 +0200 Subject: [PATCH 052/146] [Validator] Add missing romanian translations --- .../Resources/translations/validators.ro.xlf | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 26b069ab02774..2f7660ea08e17 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -334,6 +334,58 @@ This value should be valid JSON. Această valoare trebuie să fie un JSON valid. + + This collection should contain only unique elements. + Acest set ar trebui să conțină numai elemente unice. + + + This value should be positive. + Această valoare ar trebui să fie pozitivă. + + + This value should be either positive or zero. + Această valoare trebuie să fie pozitivă sau zero. + + + This value should be negative. + Această valoare ar trebui să fie negativă. + + + This value should be either negative or zero. + Această valoare trebuie să fie negativă sau zero. + + + This value is not a valid timezone. + Această valoare nu este un fus orar valid. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Această parolă a fost compromisă și nu poate fi utilizată. Vă rugăm să utilizați o altă parolă. + + + This value should be between {{ min }} and {{ max }}. + Această valoare trebuie să fie între {{ min }} și {{ max }}. + + + This value is not a valid hostname. + Această valoare nu este un numele gazdei valid. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Numărul de elemente din această colecție ar trebui să fie un multiplu al {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Această valoare trebuie să îndeplinească cel puțin una dintre următoarele reguli: + + + Each element of this collection should satisfy its own set of constraints. + Fiecare element din acest set ar trebui să îndeplinească propriul set de reguli. + + + This value is not a valid International Securities Identification Number (ISIN). + Această valoare nu este un număr internațional de identificare (ISIN) valabil. + From 5dfafd334ec7e7c4d9784314912f4caec248d180 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Oct 2020 23:34:11 +0200 Subject: [PATCH 053/146] [RateLimiter] Adding annotations --- .../RateLimiter/FixedWindowLimiter.php | 10 +++++++++- .../Component/RateLimiter/SlidingWindow.php | 4 +--- .../RateLimiter/SlidingWindowLimiter.php | 17 +++-------------- .../Component/RateLimiter/TokenBucket.php | 14 +++++++++++++- .../RateLimiter/TokenBucketLimiter.php | 4 ++++ src/Symfony/Component/RateLimiter/Window.php | 4 ++++ 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php index bb0135d76980b..fc44391f16c59 100644 --- a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php @@ -26,8 +26,16 @@ final class FixedWindowLimiter implements LimiterInterface { private $id; private $limit; - private $interval; private $storage; + + /** + * @var int seconds + */ + private $interval; + + /** + * @var LockInterface + */ private $lock; use ResetLimiterTrait; diff --git a/src/Symfony/Component/RateLimiter/SlidingWindow.php b/src/Symfony/Component/RateLimiter/SlidingWindow.php index 53b3f89293ae1..2b584d9c34aee 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindow.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindow.php @@ -16,13 +16,11 @@ /** * @author Tobias Nyholm * + * @internal * @experimental in 5.2 */ final class SlidingWindow implements LimiterStateInterface { - /** - * @var string - */ private $id; /** diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php index 4d89e89615fcb..f9d2ccac6d746 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php @@ -32,28 +32,17 @@ */ final class SlidingWindowLimiter implements LimiterInterface { - /** - * @var string - */ private $id; - - /** - * @var int - */ private $limit; + private $storage; /** - * @var \DateInterval + * @var int seconds */ private $interval; /** - * @var StorageInterface - */ - private $storage; - - /** - * @var LockInterface|null + * @var LockInterface */ private $lock; diff --git a/src/Symfony/Component/RateLimiter/TokenBucket.php b/src/Symfony/Component/RateLimiter/TokenBucket.php index c7fbcb5ebc453..de5e52a32fc13 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/TokenBucket.php @@ -20,9 +20,21 @@ final class TokenBucket implements LimiterStateInterface { private $id; + private $rate; + + /** + * @var int + */ private $tokens; + + /** + * @var int + */ private $burstSize; - private $rate; + + /** + * @var float + */ private $timer; /** diff --git a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php index 64b3046ec336d..0d04763b46093 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php @@ -27,6 +27,10 @@ final class TokenBucketLimiter implements LimiterInterface private $maxBurst; private $rate; private $storage; + + /** + * @var LockInterface + */ private $lock; use ResetLimiterTrait; diff --git a/src/Symfony/Component/RateLimiter/Window.php b/src/Symfony/Component/RateLimiter/Window.php index 46ca1b38204b6..2038df6ea341c 100644 --- a/src/Symfony/Component/RateLimiter/Window.php +++ b/src/Symfony/Component/RateLimiter/Window.php @@ -23,6 +23,10 @@ final class Window implements LimiterStateInterface private $hitCount = 0; private $intervalInSeconds; private $maxSize; + + /** + * @var float + */ private $timer; public function __construct(string $id, int $intervalInSeconds, int $windowSize, ?float $timer = null) From 2b9058d6b6861ea8f4d7c6f76a0230dc72a53fcb Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Oct 2020 23:20:40 +0200 Subject: [PATCH 054/146] [RateLimiter] Allow configuration value "no_limit" --- .../FrameworkBundle/DependencyInjection/Configuration.php | 2 +- src/Symfony/Component/RateLimiter/RateLimiter.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0739256323e47..a134940add3b7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1846,7 +1846,7 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode) ->enumNode('strategy') ->info('The rate limiting algorithm to use for this rate') ->isRequired() - ->values(['fixed_window', 'token_bucket', 'sliding_window']) + ->values(['fixed_window', 'token_bucket', 'sliding_window', 'no_limit']) ->end() ->integerNode('limit') ->info('The maximum allowed hits in a fixed interval or burst') diff --git a/src/Symfony/Component/RateLimiter/RateLimiter.php b/src/Symfony/Component/RateLimiter/RateLimiter.php index 45edecd877942..078d70ad0891a 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiter.php +++ b/src/Symfony/Component/RateLimiter/RateLimiter.php @@ -54,8 +54,11 @@ public function create(?string $key = null): LimiterInterface case 'sliding_window': return new SlidingWindowLimiter($id, $this->config['limit'], $this->config['interval'], $this->storage, $lock); + case 'no_limit': + return new NoLimiter(); + default: - throw new \LogicException(sprintf('Limiter strategy "%s" does not exists, it must be either "token_bucket", "sliding_window" or "fixed_window".', $this->config['strategy'])); + throw new \LogicException(sprintf('Limiter strategy "%s" does not exists, it must be either "token_bucket", "sliding_window", "fixed_window" or "no_limit".', $this->config['strategy'])); } } From fb540bba73d4d4d2d3fecac77a488b27eedabf6c Mon Sep 17 00:00:00 2001 From: Greg ORIOL Date: Wed, 21 Oct 2020 18:56:54 +0200 Subject: [PATCH 055/146] Fix delete method on RateLimiter's cache storage --- src/Symfony/Component/RateLimiter/Storage/CacheStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php b/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php index 34e27798e6375..b61539d659243 100644 --- a/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php +++ b/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php @@ -52,6 +52,6 @@ public function fetch(string $limiterStateId): ?LimiterStateInterface public function delete(string $limiterStateId): void { - $this->pool->deleteItem($limiterStateId); + $this->pool->deleteItem(sha1($limiterStateId)); } } From 067153f4523ff13a68275d6786439e358fa77606 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Oct 2020 11:54:30 +0200 Subject: [PATCH 056/146] Make sure we actually can use sliding_window and no_limit --- .../Component/RateLimiter/RateLimiter.php | 2 +- .../RateLimiter/Tests/RateLimiterTest.php | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php diff --git a/src/Symfony/Component/RateLimiter/RateLimiter.php b/src/Symfony/Component/RateLimiter/RateLimiter.php index 078d70ad0891a..e7a177883ebc9 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiter.php +++ b/src/Symfony/Component/RateLimiter/RateLimiter.php @@ -80,7 +80,7 @@ protected static function configureOptions(OptionsResolver $options): void ->define('id')->required() ->define('strategy') ->required() - ->allowedValues('token_bucket', 'fixed_window') + ->allowedValues('token_bucket', 'fixed_window', 'sliding_window', 'no_limit') ->define('limit')->allowedTypes('int') ->define('interval')->allowedTypes('string')->normalize($intervalNormalizer) diff --git a/src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php new file mode 100644 index 0000000000000..0c84ce33a9d38 --- /dev/null +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\RateLimiter\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; +use Symfony\Component\RateLimiter\FixedWindowLimiter; +use Symfony\Component\RateLimiter\NoLimiter; +use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\SlidingWindowLimiter; +use Symfony\Component\RateLimiter\Storage\InMemoryStorage; +use Symfony\Component\RateLimiter\TokenBucketLimiter; + +class RateLimiterTest extends TestCase +{ + /** + * @dataProvider validConfigProvider + */ + public function testValidConfig(string $expectedClass, array $config) + { + $factory = new RateLimiter($config, new InMemoryStorage()); + $rateLimiter = $factory->create('key'); + $this->assertInstanceOf($expectedClass, $rateLimiter); + } + + public function validConfigProvider() + { + yield [TokenBucketLimiter::class, [ + 'strategy' => 'token_bucket', + 'id' => 'test', + 'limit' => 5, + 'rate' => [ + 'interval' => '5 seconds', + ], + ]]; + yield [FixedWindowLimiter::class, [ + 'strategy' => 'fixed_window', + 'id' => 'test', + 'limit' => 5, + 'interval' => '5 seconds', + ]]; + yield [SlidingWindowLimiter::class, [ + 'strategy' => 'sliding_window', + 'id' => 'test', + 'limit' => 5, + 'interval' => '5 seconds', + ]]; + yield [NoLimiter::class, [ + 'strategy' => 'no_limit', + 'id' => 'test', + ]]; + } + + /** + * @dataProvider invalidConfigProvider + */ + public function testInvalidConfig(string $exceptionClass, array $config) + { + $this->expectException($exceptionClass); + $factory = new RateLimiter($config, new InMemoryStorage()); + $factory->create('key'); + } + + public function invalidConfigProvider() + { + yield [MissingOptionsException::class, [ + 'strategy' => 'token_bucket', + ]]; + } +} From 88c1e2439ee69a56392e470d5f03bdfbc37ab14e Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Oct 2020 12:12:23 +0200 Subject: [PATCH 057/146] Added a test --- .../RateLimiter/Tests/Storage/CacheStorageTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php index 97de6e554fda7..dc2fcc3cfa55e 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php @@ -76,4 +76,11 @@ public function testFetchNonExistingState() $this->assertNull($this->storage->fetch('test')); } + + public function testDelete() + { + $this->pool->expects($this->once())->method('deleteItem')->with(sha1('test'))->willReturn(true); + + $this->assertNull($this->storage->delete('test')); + } } From b61d9d1ea3a489346bad2e1b301574a4d2f40323 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Oct 2020 12:14:59 +0200 Subject: [PATCH 058/146] minor --- .../Component/RateLimiter/Tests/Storage/CacheStorageTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php index dc2fcc3cfa55e..70f9246e37436 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php @@ -81,6 +81,6 @@ public function testDelete() { $this->pool->expects($this->once())->method('deleteItem')->with(sha1('test'))->willReturn(true); - $this->assertNull($this->storage->delete('test')); + $this->storage->delete('test'); } } From 52e7d78dcabdb3f4e5def5c5bc240fe8ded4b55f Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 22 Oct 2020 13:20:03 +0200 Subject: [PATCH 059/146] Add missing exporter function for PHPUnit 7 --- .../Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php index 48c79a76dd0cf..9877049153d00 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php @@ -11,6 +11,8 @@ namespace Symfony\Bridge\PhpUnit\Legacy; +use SebastianBergmann\Exporter\Exporter; + /** * @internal */ @@ -31,6 +33,15 @@ protected function additionalFailureDescription($other): string return $this->doAdditionalFailureDescription($other); } + protected function exporter(): Exporter + { + if (null !== $this->exporter) { + $this->exporter = new Exporter(); + } + + return $this->exporter; + } + protected function failureDescription($other): string { return $this->doFailureDescription($other); From 22a2740888ba3f7942573bd2e5106c2a5d064215 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 22 Oct 2020 13:57:57 +0200 Subject: [PATCH 060/146] [String] fix before/after[Last]() returning the empty string instead of the original one on non-match --- .../Component/String/AbstractString.php | 4 -- .../String/Tests/AbstractAsciiTestCase.php | 48 +++++++++---------- .../String/Tests/AbstractUnicodeTestCase.php | 10 ++-- .../String/Tests/UnicodeStringTest.php | 12 ++--- 4 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/String/AbstractString.php b/src/Symfony/Component/String/AbstractString.php index c87f1506fb6f8..d3d95d40a4670 100644 --- a/src/Symfony/Component/String/AbstractString.php +++ b/src/Symfony/Component/String/AbstractString.php @@ -98,7 +98,6 @@ public static function wrap(array $values): array public function after($needle, bool $includeNeedle = false, int $offset = 0): self { $str = clone $this; - $str->string = ''; $i = \PHP_INT_MAX; foreach ((array) $needle as $n) { @@ -130,7 +129,6 @@ public function after($needle, bool $includeNeedle = false, int $offset = 0): se public function afterLast($needle, bool $includeNeedle = false, int $offset = 0): self { $str = clone $this; - $str->string = ''; $i = null; foreach ((array) $needle as $n) { @@ -167,7 +165,6 @@ abstract public function append(string ...$suffix): self; public function before($needle, bool $includeNeedle = false, int $offset = 0): self { $str = clone $this; - $str->string = ''; $i = \PHP_INT_MAX; foreach ((array) $needle as $n) { @@ -199,7 +196,6 @@ public function before($needle, bool $includeNeedle = false, int $offset = 0): s public function beforeLast($needle, bool $includeNeedle = false, int $offset = 0): self { $str = clone $this; - $str->string = ''; $i = null; foreach ((array) $needle as $n) { diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 44f14c18af3a2..7dbef2a87d530 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -766,12 +766,12 @@ public function testBeforeAfter(string $expected, string $needle, string $origin public static function provideBeforeAfter() { return [ - ['', '', 'hello world', 0, true], - ['', '', 'hello world', 0, false], - ['', 'w', 'hello World', 0, true], - ['', 'w', 'hello World', 0, false], - ['', 'o', 'hello world', 10, true], - ['', 'o', 'hello world', 10, false], + ['hello world', '', 'hello world', 0, true], + ['hello world', '', 'hello world', 0, false], + ['hello World', 'w', 'hello World', 0, true], + ['hello World', 'w', 'hello World', 0, false], + ['hello world', 'o', 'hello world', 10, true], + ['hello world', 'o', 'hello world', 10, false], ['hello ', 'w', 'hello world', 0, true], ['world', 'w', 'hello world', 0, false], ['hello W', 'O', 'hello WORLD', 0, true], @@ -794,12 +794,12 @@ public function testBeforeAfterIgnoreCase(string $expected, string $needle, stri public static function provideBeforeAfterIgnoreCase() { return [ - ['', '', 'hello world', 0, true], - ['', '', 'hello world', 0, false], - ['', 'foo', 'hello world', 0, true], - ['', 'foo', 'hello world', 0, false], - ['', 'o', 'hello world', 10, true], - ['', 'o', 'hello world', 10, false], + ['hello world', '', 'hello world', 0, true], + ['hello world', '', 'hello world', 0, false], + ['hello world', 'foo', 'hello world', 0, true], + ['hello world', 'foo', 'hello world', 0, false], + ['hello world', 'o', 'hello world', 10, true], + ['hello world', 'o', 'hello world', 10, false], ['hello ', 'w', 'hello world', 0, true], ['world', 'w', 'hello world', 0, false], ['hello ', 'W', 'hello world', 0, true], @@ -822,12 +822,12 @@ public function testBeforeAfterLast(string $expected, string $needle, string $or public static function provideBeforeAfterLast() { return [ - ['', '', 'hello world', 0, true], - ['', '', 'hello world', 0, false], - ['', 'L', 'hello world', 0, true], - ['', 'L', 'hello world', 0, false], - ['', 'o', 'hello world', 10, true], - ['', 'o', 'hello world', 10, false], + ['hello world', '', 'hello world', 0, true], + ['hello world', '', 'hello world', 0, false], + ['hello world', 'L', 'hello world', 0, true], + ['hello world', 'L', 'hello world', 0, false], + ['hello world', 'o', 'hello world', 10, true], + ['hello world', 'o', 'hello world', 10, false], ['hello wor', 'l', 'hello world', 0, true], ['ld', 'l', 'hello world', 0, false], ['hello w', 'o', 'hello world', 0, true], @@ -851,12 +851,12 @@ public function testBeforeAfterLastIgnoreCase(string $expected, string $needle, public static function provideBeforeAfterLastIgnoreCase() { return [ - ['', '', 'hello world', 0, true], - ['', '', 'hello world', 0, false], - ['', 'FOO', 'hello world', 0, true], - ['', 'FOO', 'hello world', 0, false], - ['', 'o', 'hello world', 10, true], - ['', 'o', 'hello world', 10, false], + ['hello world', '', 'hello world', 0, true], + ['hello world', '', 'hello world', 0, false], + ['hello world', 'FOO', 'hello world', 0, true], + ['hello world', 'FOO', 'hello world', 0, false], + ['hello world', 'o', 'hello world', 10, true], + ['hello world', 'o', 'hello world', 10, false], ['hello wor', 'l', 'hello world', 0, true], ['ld', 'l', 'hello world', 0, false], ['hello wor', 'L', 'hello world', 0, true], diff --git a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php index 84e64b02e9f6a..c0a3452f78923 100644 --- a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php @@ -396,8 +396,8 @@ public static function provideBeforeAfterIgnoreCase(): array ['dé', 'jÀ', 'déjàdéjà', 0, true], ['éjàdéjà', 'é', 'déjàdéjà', 0, false], ['d', 'é', 'déjàdéjà', 0, true], - ['', 'Ç', 'déjàdéjà', 0, false], - ['', 'Ç', 'déjàdéjà', 0, true], + ['déjàdéjà', 'Ç', 'déjàdéjà', 0, false], + ['déjàdéjà', 'Ç', 'déjàdéjà', 0, true], ] ); } @@ -407,8 +407,8 @@ public static function provideBeforeAfterLast(): array return array_merge( parent::provideBeforeAfterLast(), [ - ['', 'Ç', 'déjàdéjà', 0, false], - ['', 'Ç', 'déjàdéjà', 0, true], + ['déjàdéjà', 'Ç', 'déjàdéjà', 0, false], + ['déjàdéjà', 'Ç', 'déjàdéjà', 0, true], ['éjà', 'é', 'déjàdéjà', 0, false], ['déjàd', 'é', 'déjàdéjà', 0, true], ] @@ -420,7 +420,7 @@ public static function provideBeforeAfterLastIgnoreCase(): array return array_merge( parent::provideBeforeAfterLastIgnoreCase(), [ - ['', 'Ç', 'déjàdéjà', 0, false], + ['déjàdéjà', 'Ç', 'déjàdéjà', 0, false], ['éjà', 'é', 'déjàdéjà', 0, false], ['éjà', 'É', 'déjàdéjà', 0, false], ] diff --git a/src/Symfony/Component/String/Tests/UnicodeStringTest.php b/src/Symfony/Component/String/Tests/UnicodeStringTest.php index 5f3321d6da1c0..bcf3e2ecd441a 100644 --- a/src/Symfony/Component/String/Tests/UnicodeStringTest.php +++ b/src/Symfony/Component/String/Tests/UnicodeStringTest.php @@ -186,8 +186,8 @@ public static function provideBeforeAfterIgnoreCase(): array return array_merge( parent::provideBeforeAfterIgnoreCase(), [ - ['', 'छेछे', 'दछेच्नुअ', 0, false], - ['', 'छेछे', 'दछेच्नुअ', 0, true], + ['दछेच्नुअ', 'छेछे', 'दछेच्नुअ', 0, false], + ['दछेच्नुअ', 'छेछे', 'दछेच्नुअ', 0, true], ['छेच्नुअ', 'छे', 'दछेच्नुअ', 0, false], ['द', 'छे', 'दछेच्नुअ', 0, true], ] @@ -199,8 +199,8 @@ public static function provideBeforeAfterLast(): array return array_merge( parent::provideBeforeAfterLast(), [ - ['', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, false], - ['', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, true], + ['दछेच्नुअ-दछेच्नु-अदछेच्नु', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, false], + ['दछेच्नुअ-दछेच्नु-अदछेच्नु', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, true], ['-दछेच्नु', '-द', 'दछेच्नुअ-दछेच्नु-अद-दछेच्नु', 0, false], ['दछेच्नुअ-दछेच्नु-अद', '-द', 'दछेच्नुअ-दछेच्नु-अद-दछेच्नु', 0, true], ] @@ -212,8 +212,8 @@ public static function provideBeforeAfterLastIgnoreCase(): array return array_merge( parent::provideBeforeAfterLastIgnoreCase(), [ - ['', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, false], - ['', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, true], + ['दछेच्नुअ-दछेच्नु-अदछेच्नु', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, false], + ['दछेच्नुअ-दछेच्नु-अदछेच्नु', 'छेछे', 'दछेच्नुअ-दछेच्नु-अदछेच्नु', 0, true], ['-दछेच्नु', '-द', 'दछेच्नुअ-दछेच्नु-अद-दछेच्नु', 0, false], ['दछेच्नुअ-दछेच्नु-अद', '-द', 'दछेच्नुअ-दछेच्नु-अद-दछेच्नु', 0, true], ] From e2f0454f133444db6c071990dfe7b67591790371 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 22 Oct 2020 14:27:47 +0200 Subject: [PATCH 061/146] [PhpUnitBridge] remove wrong changelog entry --- src/Symfony/Bridge/PhpUnit/CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md index c343171feb6a0..2808ad0c50903 100644 --- a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md +++ b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md @@ -1,11 +1,6 @@ CHANGELOG ========= -5.2.0 ------ - - * polyfill new phpunit 9.1 assertions - 5.1.0 ----- From 8a49a263a2d77607a05eac9501751fd2e856af27 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 22 Oct 2020 13:32:31 +0200 Subject: [PATCH 062/146] Add expectDeprecation, expectNotice, expectWarning, and expectError to TestCase polyfill --- .../PhpUnit/Legacy/PolyfillTestCaseTrait.php | 98 ++++++++++++++++++- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php index cb3fbf44903bd..ad2150436833d 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php @@ -11,6 +11,9 @@ namespace Symfony\Bridge\PhpUnit\Legacy; +use PHPUnit\Framework\Error\Error; +use PHPUnit\Framework\Error\Notice; +use PHPUnit\Framework\Error\Warning; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -66,9 +69,7 @@ protected function createPartialMock($originalClassName, array $methods) */ public function expectException($exception) { - $property = new \ReflectionProperty(TestCase::class, 'expectedException'); - $property->setAccessible(true); - $property->setValue($this, $exception); + $this->doExpectException($exception); } /** @@ -116,4 +117,95 @@ public function expectExceptionMessageRegExp($messageRegExp) $property->setAccessible(true); $property->setValue($this, $messageRegExp); } + + /** + * @return void + */ + public function expectNotice() + { + $this->doExpectException(Notice::class); + } + + /** + * @param string $message + * + * @return void + */ + public function expectNoticeMessage($message) + { + $this->expectExceptionMessage($message); + } + + /** + * @param string $regularExpression + * + * @return void + */ + public function expectNoticeMessageMatches($regularExpression) + { + $this->expectExceptionMessageMatches($regularExpression); + } + + /** + * @return void + */ + public function expectWarning() + { + $this->doExpectException(Warning::class); + } + + /** + * @param string $message + * + * @return void + */ + public function expectWarningMessage($message) + { + $this->expectExceptionMessage($message); + } + + /** + * @param string $regularExpression + * + * @return void + */ + public function expectWarningMessageMatches($regularExpression) + { + $this->expectExceptionMessageMatches($regularExpression); + } + + /** + * @return void + */ + public function expectError() + { + $this->doExpectException(Error::class); + } + + /** + * @param string $message + * + * @return void + */ + public function expectErrorMessage($message) + { + $this->expectExceptionMessage($message); + } + + /** + * @param string $regularExpression + * + * @return void + */ + public function expectErrorMessageMatches($regularExpression) + { + $this->expectExceptionMessageMatches($regularExpression); + } + + private function doExpectException($exception) + { + $property = new \ReflectionProperty(TestCase::class, 'expectedException'); + $property->setAccessible(true); + $property->setValue($this, $exception); + } } From f79ad8000950bad771376d36c583da10909e6466 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 22 Oct 2020 14:14:44 +0200 Subject: [PATCH 063/146] Support PHPUnit 8 and PHPUnit 9 in constraint compatibility trait --- .../Bridge/PhpUnit/ConstraintTrait.php | 12 +++- .../PhpUnit/Legacy/ConstraintLogicTrait.php | 62 +++++++++++++++++++ .../PhpUnit/Legacy/ConstraintTraitForV6.php | 27 ++++++++ .../PhpUnit/Legacy/ConstraintTraitForV7.php | 35 +++-------- .../PhpUnit/Legacy/ConstraintTraitForV8.php | 53 ++++++++++++++++ .../PhpUnit/Legacy/ConstraintTraitForV9.php | 50 +++++++++++++++ 6 files changed, 213 insertions(+), 26 deletions(-) create mode 100644 src/Symfony/Bridge/PhpUnit/Legacy/ConstraintLogicTrait.php create mode 100644 src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV8.php create mode 100644 src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV9.php diff --git a/src/Symfony/Bridge/PhpUnit/ConstraintTrait.php b/src/Symfony/Bridge/PhpUnit/ConstraintTrait.php index 64b24ee166858..446dbf2f4fe03 100644 --- a/src/Symfony/Bridge/PhpUnit/ConstraintTrait.php +++ b/src/Symfony/Bridge/PhpUnit/ConstraintTrait.php @@ -20,9 +20,19 @@ trait ConstraintTrait { use Legacy\ConstraintTraitForV6; } -} else { +} elseif ($r->getProperty('exporter')->isProtected()) { trait ConstraintTrait { use Legacy\ConstraintTraitForV7; } +} elseif (\PHP_VERSION < 70100 || !$r->getMethod('evaluate')->hasReturnType()) { + trait ConstraintTrait + { + use Legacy\ConstraintTraitForV8; + } +} else { + trait ConstraintTrait + { + use Legacy\ConstraintTraitForV9; + } } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintLogicTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintLogicTrait.php new file mode 100644 index 0000000000000..e124358c4f724 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintLogicTrait.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Legacy; + +/** + * @internal + */ +trait ConstraintLogicTrait +{ + private function doEvaluate($other, $description, $returnResult) + { + $success = false; + + if ($this->matches($other)) { + $success = true; + } + + if ($returnResult) { + return $success; + } + + if (!$success) { + $this->fail($other, $description); + } + + return null; + } + + private function doAdditionalFailureDescription($other): string + { + return ''; + } + + private function doCount(): int + { + return 1; + } + + private function doFailureDescription($other): string + { + return $this->exporter()->export($other).' '.$this->toString(); + } + + private function doMatches($other): bool + { + return false; + } + + private function doToString(): string + { + return ''; + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV6.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV6.php index 71b7c3c39d738..53819e4b3c4d7 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV6.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV6.php @@ -18,6 +18,14 @@ */ trait ConstraintTraitForV6 { + /** + * @return bool|null + */ + public function evaluate($other, $description = '', $returnResult = false) + { + return $this->doEvaluate($other, $description, $returnResult); + } + /** * @return int */ @@ -86,6 +94,25 @@ private function doCount() return 1; } + private function doEvaluate($other, $description, $returnResult) + { + $success = false; + + if ($this->matches($other)) { + $success = true; + } + + if ($returnResult) { + return $success; + } + + if (!$success) { + $this->fail($other, $description); + } + + return null; + } + private function doFailureDescription($other) { return $this->exporter()->export($other).' '.$this->toString(); diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php index 48c79a76dd0cf..f915d763befe1 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV7.php @@ -16,6 +16,16 @@ */ trait ConstraintTraitForV7 { + use ConstraintLogicTrait; + + /** + * @return bool|null + */ + public function evaluate($other, $description = '', $returnResult = false) + { + return $this->doEvaluate($other, $description, $returnResult); + } + public function count(): int { return $this->doCount(); @@ -40,29 +50,4 @@ protected function matches($other): bool { return $this->doMatches($other); } - - private function doAdditionalFailureDescription($other): string - { - return ''; - } - - private function doCount(): int - { - return 1; - } - - private function doFailureDescription($other): string - { - return $this->exporter()->export($other).' '.$this->toString(); - } - - private function doMatches($other): bool - { - return false; - } - - private function doToString(): string - { - return ''; - } } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV8.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV8.php new file mode 100644 index 0000000000000..d31cc1215877b --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV8.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Legacy; + +/** + * @internal + */ +trait ConstraintTraitForV8 +{ + use ConstraintLogicTrait; + + /** + * @return bool|null + */ + public function evaluate($other, $description = '', $returnResult = false) + { + return $this->doEvaluate($other, $description, $returnResult); + } + + public function count(): int + { + return $this->doCount(); + } + + public function toString(): string + { + return $this->doToString(); + } + + protected function additionalFailureDescription($other): string + { + return $this->doAdditionalFailureDescription($other); + } + + protected function failureDescription($other): string + { + return $this->doFailureDescription($other); + } + + protected function matches($other): bool + { + return $this->doMatches($other); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV9.php b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV9.php new file mode 100644 index 0000000000000..66da873e4243e --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Legacy/ConstraintTraitForV9.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Legacy; + +/** + * @internal + */ +trait ConstraintTraitForV9 +{ + use ConstraintLogicTrait; + + public function evaluate($other, string $description = '', bool $returnResult = false): ?bool + { + return $this->doEvaluate($other, $description, $returnResult); + } + + public function count(): int + { + return $this->doCount(); + } + + public function toString(): string + { + return $this->doToString(); + } + + protected function additionalFailureDescription($other): string + { + return $this->doAdditionalFailureDescription($other); + } + + protected function failureDescription($other): string + { + return $this->doFailureDescription($other); + } + + protected function matches($other): bool + { + return $this->doMatches($other); + } +} From e4c0262dc196a27dee8feecdf3db898b426ff6fd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 22 Oct 2020 15:39:59 +0200 Subject: [PATCH 064/146] [HttpClient] never trace content of event-stream responses --- src/Symfony/Component/HttpClient/EventSourceHttpClient.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php index 5dfa929c54618..d6f27a7fae99f 100644 --- a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php +++ b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php @@ -60,6 +60,10 @@ public function request(string $method, string $url, array $options = []): Respo if ($accept = self::normalizeHeaders($options['headers'] ?? [])['accept'] ?? []) { $state->buffer = \in_array($accept, [['Accept: text/event-stream'], ['accept: text/event-stream']], true) ? '' : null; + + if (null !== $state->buffer) { + $options['extra']['trace_content'] = false; + } } return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use ($state, $method, $url, $options) { From 713c2623e5a35a52f56a918177de7c69e76f6908 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 22 Oct 2020 20:37:20 +0200 Subject: [PATCH 065/146] [TwigBridge] Remove "transchoice" from the code base --- .../TranslationDefaultDomainNodeVisitor.php | 17 +++++++---------- .../Twig/NodeVisitor/TranslationNodeVisitor.php | 10 ---------- .../Bridge/Twig/UndefinedCallableHandler.php | 1 - 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php index 55bc3ae9a8959..213365ed9f1ef 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -64,21 +64,18 @@ protected function doEnterNode(Node $node, Environment $env): Node return $node; } - if ($node instanceof FilterExpression && \in_array($node->getNode('filter')->getAttribute('value'), ['trans', 'transchoice'])) { + if ($node instanceof FilterExpression && 'trans' === $node->getNode('filter')->getAttribute('value')) { $arguments = $node->getNode('arguments'); - $ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2; if ($this->isNamedArguments($arguments)) { - if (!$arguments->hasNode('domain') && !$arguments->hasNode($ind)) { + if (!$arguments->hasNode('domain') && !$arguments->hasNode(1)) { $arguments->setNode('domain', $this->scope->get('domain')); } - } else { - if (!$arguments->hasNode($ind)) { - if (!$arguments->hasNode($ind - 1)) { - $arguments->setNode($ind - 1, new ArrayExpression([], $node->getTemplateLine())); - } - - $arguments->setNode($ind, $this->scope->get('domain')); + } elseif (!$arguments->hasNode(1)) { + if (!$arguments->hasNode(0)) { + $arguments->setNode(0, new ArrayExpression([], $node->getTemplateLine())); } + + $arguments->setNode(1, $this->scope->get('domain')); } } elseif ($node instanceof TransNode) { if (!$node->hasNode('domain')) { diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php index 89a15cd622c5d..3d5edb4ae1994 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -66,16 +66,6 @@ protected function doEnterNode(Node $node, Environment $env): Node $node->getNode('node')->getAttribute('value'), $this->getReadDomainFromArguments($node->getNode('arguments'), 1), ]; - } elseif ( - $node instanceof FilterExpression && - 'transchoice' === $node->getNode('filter')->getAttribute('value') && - $node->getNode('node') instanceof ConstantExpression - ) { - // extract constant nodes with a trans filter - $this->messages[] = [ - $node->getNode('node')->getAttribute('value'), - $this->getReadDomainFromArguments($node->getNode('arguments'), 2), - ]; } elseif ($node instanceof TransNode) { // extract trans nodes $this->messages[] = [ diff --git a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php index fa3049d3dd7c2..a058acb40af28 100644 --- a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php +++ b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php @@ -22,7 +22,6 @@ class UndefinedCallableHandler private static $filterComponents = [ 'humanize' => 'form', 'trans' => 'translation', - 'transchoice' => 'translation', 'yaml_encode' => 'yaml', 'yaml_dump' => 'yaml', ]; From 02a8ca39f4d238860dd320ae80b7603c968dd1df Mon Sep 17 00:00:00 2001 From: Jos Elstgeest Date: Thu, 22 Oct 2020 22:50:11 +0200 Subject: [PATCH 066/146] add missing dutch translations --- .../Resources/translations/validators.nl.xlf | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 3b2eb4131bd3a..c1a4c13dafa1f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -366,6 +366,26 @@ This value should be between {{ min }} and {{ max }}. Deze waarde moet zich tussen {{ min }} en {{ max }} bevinden. + + This value is not a valid hostname. + Deze waarde is geen geldige hostnaam. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Het aantal elementen van deze collectie moet een veelvoud zijn van {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Deze waarde moet voldoen aan tenminste een van de volgende voorwaarden: + + + Each element of this collection should satisfy its own set of constraints. + Elk element van deze collectie moet voldoen aan zijn eigen set voorwaarden. + + + This value is not a valid International Securities Identification Number (ISIN). + Deze waarde is geen geldig International Securities Identification Number (ISIN). + From 97b4306c3037b2bcdf8b6c829d602f6dfc173551 Mon Sep 17 00:00:00 2001 From: Marcin Kruk Date: Wed, 21 Oct 2020 20:47:39 +0000 Subject: [PATCH 067/146] [Serializer] fix decoding float XML attributes starting with 0 --- .../Component/Serializer/Encoder/XmlEncoder.php | 2 +- .../Serializer/Tests/Encoder/XmlEncoderTest.php | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index 1cf8ee126fb0e..6d256ff2eac2d 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -304,7 +304,7 @@ private function parseXmlAttributes(\DOMNode $node, array $context = []) $typeCastAttributes = $this->resolveXmlTypeCastAttributes($context); foreach ($node->attributes as $attr) { - if (!is_numeric($attr->nodeValue) || !$typeCastAttributes || (isset($attr->nodeValue[1]) && '0' === $attr->nodeValue[0])) { + if (!is_numeric($attr->nodeValue) || !$typeCastAttributes || (isset($attr->nodeValue[1]) && '0' === $attr->nodeValue[0] && '.' !== $attr->nodeValue[1])) { $data['@'.$attr->nodeName] = $attr->nodeValue; continue; diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 94f2e6c18a6ad..c9b2de2e83316 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -268,10 +268,10 @@ public function testDecodeFloatAttribute() { $source = << -Name +Name XML; - $this->assertSame(['@index' => -12.11, '#' => 'Name'], $this->encoder->decode($source, 'xml')); + $this->assertSame(['@index' => 12.11, '#' => 'Name'], $this->encoder->decode($source, 'xml')); } public function testDecodeNegativeFloatAttribute() @@ -284,6 +284,16 @@ public function testDecodeNegativeFloatAttribute() $this->assertSame(['@index' => -12.11, '#' => 'Name'], $this->encoder->decode($source, 'xml')); } + public function testDecodeFloatAttributeWithZeroWholeNumber() + { + $source = << +Name +XML; + + $this->assertSame(['@index' => 0.123, '#' => 'Name'], $this->encoder->decode($source, 'xml')); + } + public function testNoTypeCastAttribute() { $source = << Date: Fri, 23 Oct 2020 02:04:18 +0200 Subject: [PATCH 068/146] Add Stopwatch on TraceableClient --- .../Resources/views/Collector/time.js | 1 + .../DependencyInjection/HttpClientPass.php | 3 +- .../HttpClient/Response/TraceableResponse.php | 100 ++++++++++++++---- .../Tests/TraceableHttpClientTest.php | 90 ++++++++++++++++ .../HttpClient/TraceableHttpClient.php | 7 +- 5 files changed, 179 insertions(+), 22 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js index 588a9d22ed350..156c9343ff139 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js @@ -413,6 +413,7 @@ class Theme { 'doctrine': '#ff6633', 'messenger_middleware': '#bdb81e', 'controller.argument_value_resolver': '#8c5de6', + 'http_client': '#ffa333', }; this.customCategoryColors = [ diff --git a/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php b/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php index e19779786bd65..787fbc3853512 100644 --- a/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php +++ b/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpClient\TraceableHttpClient; @@ -36,7 +37,7 @@ public function process(ContainerBuilder $container) foreach ($container->findTaggedServiceIds($this->clientTag) as $id => $tags) { $container->register('.debug.'.$id, TraceableHttpClient::class) - ->setArguments([new Reference('.debug.'.$id.'.inner')]) + ->setArguments([new Reference('.debug.'.$id.'.inner'), new Reference('debug.stopwatch', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]) ->setDecoratedService($id); $container->getDefinition('data_collector.http_client') ->addMethodCall('registerClient', [$id, new Reference('.debug.'.$id)]); diff --git a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php index ea9afa43b1ef1..a33490b8ef9eb 100644 --- a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php +++ b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php @@ -11,10 +11,12 @@ namespace Symfony\Component\HttpClient\Response; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; use Symfony\Component\HttpClient\Exception\ClientException; use Symfony\Component\HttpClient\Exception\RedirectionException; use Symfony\Component\HttpClient\Exception\ServerException; use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\Stopwatch\StopwatchEvent; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -32,57 +34,98 @@ class TraceableResponse implements ResponseInterface, StreamableInterface private $client; private $response; private $content; + private $event; - public function __construct(HttpClientInterface $client, ResponseInterface $response, &$content) + public function __construct(HttpClientInterface $client, ResponseInterface $response, &$content, StopwatchEvent $event = null) { $this->client = $client; $this->response = $response; $this->content = &$content; + $this->event = $event; + } + + public function __destruct() + { + try { + $this->response->__destruct(); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + } } public function getStatusCode(): int { - return $this->response->getStatusCode(); + try { + return $this->response->getStatusCode(); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->lap(); + } + } } public function getHeaders(bool $throw = true): array { - return $this->response->getHeaders($throw); + try { + return $this->response->getHeaders($throw); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->lap(); + } + } } public function getContent(bool $throw = true): string { - if (false === $this->content) { - return $this->response->getContent($throw); - } + try { + if (false === $this->content) { + return $this->response->getContent($throw); + } - $this->content = $this->response->getContent(false); + $this->content = $this->response->getContent(false); - if ($throw) { - $this->checkStatusCode($this->response->getStatusCode()); - } + if ($throw) { + $this->checkStatusCode($this->response->getStatusCode()); + } - return $this->content; + return $this->content; + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + } } public function toArray(bool $throw = true): array { - if (false === $this->content) { - return $this->response->toArray($throw); - } + try { + if (false === $this->content) { + return $this->response->toArray($throw); + } - $this->content = $this->response->toArray(false); + $this->content = $this->response->toArray(false); - if ($throw) { - $this->checkStatusCode($this->response->getStatusCode()); - } + if ($throw) { + $this->checkStatusCode($this->response->getStatusCode()); + } - return $this->content; + return $this->content; + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + } } public function cancel(): void { $this->response->cancel(); + + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } } public function getInfo(string $type = null) @@ -129,9 +172,28 @@ public static function stream(HttpClientInterface $client, iterable $responses, $traceableMap[$r->response] = $r; $wrappedResponses[] = $r->response; + if ($r->event && !$r->event->isStarted()) { + $r->event->start(); + } } foreach ($client->stream($wrappedResponses, $timeout) as $r => $chunk) { + if ($traceableMap[$r]->event && $traceableMap[$r]->event->isStarted()) { + try { + if ($chunk->isTimeout() || !$chunk->isLast()) { + $traceableMap[$r]->event->lap(); + } else { + $traceableMap[$r]->event->stop(); + } + } catch (TransportExceptionInterface $e) { + $traceableMap[$r]->event->stop(); + if ($chunk instanceof ErrorChunk) { + $chunk->didThrow(false); + } else { + $chunk = new ErrorChunk($chunk->getOffset(), $e); + } + } + } yield $traceableMap[$r] => $chunk; } } diff --git a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php index 94e557cd893cf..2ba50adfe25aa 100755 --- a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php @@ -12,10 +12,12 @@ namespace Symfony\Component\HttpClient\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\ClientException; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\NativeHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\Test\TestHttpServer; @@ -115,4 +117,92 @@ public function testStream() $this->assertGreaterThan(1, \count($chunks)); $this->assertSame('Symfony is awesome!', implode('', $chunks)); } + + public function testStopwatch() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057'); + + $response->getStatusCode(); + $response->getHeaders(); + $response->getContent(); + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertCount(3, $events['GET http://localhost:8057']->getPeriods()); + $this->assertGreaterThan(0.0, $events['GET http://localhost:8057']->getDuration()); + } + + public function testStopwatchError() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057/404'); + + try { + $response->getContent(); + $this->fail('Response should have thrown an exception'); + } catch (ClientException $e) { + // no-op + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057/404', $events); + $this->assertCount(1, $events['GET http://localhost:8057/404']->getPeriods()); + } + + public function testStopwatchStream() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057'); + + $chunkCount = 0; + foreach ($sut->stream([$response]) as $chunk) { + ++$chunkCount; + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertGreaterThanOrEqual($chunkCount, \count($events['GET http://localhost:8057']->getPeriods())); + } + + public function testStopwatchStreamError() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057/404'); + + try { + $chunkCount = 0; + foreach ($sut->stream([$response]) as $chunk) { + ++$chunkCount; + } + $this->fail('Response should have thrown an exception'); + } catch (ClientException $e) { + // no-op + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057/404', $events); + $this->assertGreaterThanOrEqual($chunkCount, \count($events['GET http://localhost:8057/404']->getPeriods())); + } + + public function testStopwatchDestruct() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $sut->request('GET', 'http://localhost:8057'); + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertCount(1, $events['GET http://localhost:8057']->getPeriods()); + $this->assertGreaterThan(0.0, $events['GET http://localhost:8057']->getDuration()); + } } diff --git a/src/Symfony/Component/HttpClient/TraceableHttpClient.php b/src/Symfony/Component/HttpClient/TraceableHttpClient.php index a061fef7ea80c..34dc01ad2553f 100644 --- a/src/Symfony/Component/HttpClient/TraceableHttpClient.php +++ b/src/Symfony/Component/HttpClient/TraceableHttpClient.php @@ -15,6 +15,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Response\ResponseStream; use Symfony\Component\HttpClient\Response\TraceableResponse; +use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; use Symfony\Contracts\HttpClient\ResponseStreamInterface; @@ -27,10 +28,12 @@ final class TraceableHttpClient implements HttpClientInterface, ResetInterface, { private $client; private $tracedRequests = []; + private $stopwatch; - public function __construct(HttpClientInterface $client) + public function __construct(HttpClientInterface $client, Stopwatch $stopwatch = null) { $this->client = $client; + $this->stopwatch = $stopwatch; } /** @@ -62,7 +65,7 @@ public function request(string $method, string $url, array $options = []): Respo } }; - return new TraceableResponse($this->client, $this->client->request($method, $url, $options), $content); + return new TraceableResponse($this->client, $this->client->request($method, $url, $options), $content, null === $this->stopwatch ? null : $this->stopwatch->start("$method $url", 'http_client')); } /** From c6b32cdbd2c8708f4ec815f008663f257c0fd3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Fri, 23 Oct 2020 15:33:06 +0200 Subject: [PATCH 069/146] add missing upgrade entries and fixed changelog --- UPGRADE-5.2.md | 12 ++++++++++++ src/Symfony/Component/Notifier/CHANGELOG.md | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/UPGRADE-5.2.md b/UPGRADE-5.2.md index 36859edc762cf..cd3c523d7644b 100644 --- a/UPGRADE-5.2.md +++ b/UPGRADE-5.2.md @@ -57,6 +57,18 @@ Monolog * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` has been deprecated and replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` will become final in 6.0. * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` has been deprecated and replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` will become final in 6.0 +Notifier +-------- + + * [BC BREAK] The `TransportInterface::send()` and `AbstractTransport::doSend()` methods changed to return a `?SentMessage` instance instead of `void`. + * [BC BREAK] Changed the type-hint of the `$recipient` argument in the `as*Message()` method + of `EmailNotificationInterface` and `SmsNotificationInterface` to `EmailRecipientInterface` + and `SmsRecipientInterface`. + * [BC BREAK] Removed the `AdminRecipient`. + * [BC BREAK] Changed the type-hint of the `$recipient` argument in `NotifierInterface::send()`, + `Notifier::getChannels()`, `ChannelInterface::notifiy()` and `ChannelInterface::supports()` to + `RecipientInterface`. + PropertyAccess -------------- diff --git a/src/Symfony/Component/Notifier/CHANGELOG.md b/src/Symfony/Component/Notifier/CHANGELOG.md index 441a30d9c3da7..e381e758ca25e 100644 --- a/src/Symfony/Component/Notifier/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/CHANGELOG.md @@ -7,9 +7,9 @@ CHANGELOG * [BC BREAK] The `TransportInterface::send()` and `AbstractTransport::doSend()` methods changed to return a `?SentMessage` instance instead of `void`. * Added the Zulip notifier bridge * The `EmailRecipientInterface` and `RecipientInterface` were introduced. - * Added `email` and and `phone` properties to `Recipient`. - * [BC BREAK] Changed the type-hint of the `$recipient` argument in the `as*Message()` - of the `EmailNotificationInterface` and `SmsNotificationInterface` to `EmailRecipientInterface` + * Added `email` and `phone` properties to `Recipient`. + * [BC BREAK] Changed the type-hint of the `$recipient` argument in the `as*Message()` method + of `EmailNotificationInterface` and `SmsNotificationInterface` to `EmailRecipientInterface` and `SmsRecipientInterface`. * [BC BREAK] Removed the `AdminRecipient`. * The `EmailRecipientInterface` and `SmsRecipientInterface` now extend the `RecipientInterface`. From a7b0f16a56c6d62af2e4a8f1461c617ad6246e5c Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 23 Oct 2020 19:10:28 +0200 Subject: [PATCH 070/146] [DependencyInjection] Preload classes with union types correctly. --- .github/patch-types.php | 1 + .../DependencyInjection/Dumper/Preloader.php | 2 +- .../Tests/Dumper/PreloaderTest.php | 53 +++++++++++++++++++ .../Tests/Fixtures/Preload/A.php | 16 ++++++ .../Tests/Fixtures/Preload/B.php | 16 ++++++ .../Tests/Fixtures/Preload/C.php | 16 ++++++ .../Tests/Fixtures/Preload/D.php | 16 ++++++ .../Tests/Fixtures/Preload/Dummy.php | 30 +++++++++++ .../Tests/Fixtures/Preload/E.php | 16 ++++++ .../Tests/Fixtures/Preload/UnionDummy.php | 21 ++++++++ 10 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/A.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/B.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/C.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/D.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/Dummy.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/E.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/UnionDummy.php diff --git a/.github/patch-types.php b/.github/patch-types.php index 5c68a66c89c79..46c6980dab4a2 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -33,6 +33,7 @@ case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'): + case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'): case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'): diff --git a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php index fb39645022edf..1e0b6919fd1fe 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php @@ -94,7 +94,7 @@ private static function doPreload(string $class, array &$preloaded): void private static function preloadType(?\ReflectionType $t, array &$preloaded): void { - if (!$t || $t->isBuiltin()) { + if (!$t) { return; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php new file mode 100644 index 0000000000000..a9b3242031537 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Dumper; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Dumper\Preloader; + +class PreloaderTest extends TestCase +{ + /** + * @requires PHP 7.4 + */ + public function testPreload() + { + $r = new \ReflectionMethod(Preloader::class, 'doPreload'); + $r->setAccessible(true); + + $preloaded = []; + + $r->invokeArgs(null, ['Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\Dummy', &$preloaded]); + + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\Dummy', false)); + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\A', false)); + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\B', false)); + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\C', false)); + } + + /** + * @requires PHP 8 + */ + public function testPreloadUnion() + { + $r = new \ReflectionMethod(Preloader::class, 'doPreload'); + $r->setAccessible(true); + + $preloaded = []; + + $r->invokeArgs(null, ['Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\UnionDummy', &$preloaded]); + + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\UnionDummy', false)); + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\D', false)); + self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\E', false)); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/A.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/A.php new file mode 100644 index 0000000000000..2802a577e85b1 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/A.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class A +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/B.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/B.php new file mode 100644 index 0000000000000..66dda101ce436 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/B.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class B +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/C.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/C.php new file mode 100644 index 0000000000000..331e9fed19c95 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/C.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class C +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/D.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/D.php new file mode 100644 index 0000000000000..52e10e918149b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/D.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class D +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/Dummy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/Dummy.php new file mode 100644 index 0000000000000..35d61be5a573c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/Dummy.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class Dummy +{ + public A $a; + + public function doSomething(B $b): ?C + { + return null; + } + + public function noTypes($foo) + { + } + + public function builtinTypes(int $foo): ?string + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/E.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/E.php new file mode 100644 index 0000000000000..b4ec3b2734c57 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/E.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class E +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/UnionDummy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/UnionDummy.php new file mode 100644 index 0000000000000..24b709b0a2d69 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/UnionDummy.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class UnionDummy +{ + public D|E $de; + + public function builtinTypes(int|float $foo): string|\Stringable|null + { + } +} From 8be261b3001fbf51dd8068035238a2d74e2f86aa Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Oct 2020 12:00:53 +0200 Subject: [PATCH 071/146] [RateLimiter] Rename RateLimiter to RateLimiterFactory --- .../DependencyInjection/FrameworkExtension.php | 4 ++-- .../Resources/config/rate_limiter.php | 4 ++-- .../Security/Factory/LoginThrottlingFactory.php | 4 ++-- src/Symfony/Component/RateLimiter/README.md | 6 +++--- .../{RateLimiter.php => RateLimiterFactory.php} | 2 +- .../Component/RateLimiter/Tests/LimiterTest.php | 4 ++-- ...imiterTest.php => RateLimiterFactoryTest.php} | 8 ++++---- .../Http/RateLimiter/DefaultLoginRateLimiter.php | 16 ++++++++-------- .../LoginThrottlingListenerTest.php | 6 +++--- 9 files changed, 27 insertions(+), 27 deletions(-) rename src/Symfony/Component/RateLimiter/{RateLimiter.php => RateLimiterFactory.php} (99%) rename src/Symfony/Component/RateLimiter/Tests/{RateLimiterTest.php => RateLimiterFactoryTest.php} (89%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c8c6f74050094..4c8284c350351 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -132,7 +132,7 @@ use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface; use Symfony\Component\RateLimiter\LimiterInterface; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\RateLimiter\Storage\CacheStorage; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; use Symfony\Component\Routing\Loader\AnnotationFileLoader; @@ -2280,7 +2280,7 @@ public static function registerRateLimiter(ContainerBuilder $container, string $ $limiterConfig['id'] = $name; $limiter->replaceArgument(0, $limiterConfig); - $container->registerAliasForArgument($limiterId, RateLimiter::class, $name.'.limiter'); + $container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name.'.limiter'); } private function resolveTrustedHeaders(array $headers): int diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php index e9677ae962140..39f92323f09a5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/rate_limiter.php @@ -11,7 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; return static function (ContainerConfigurator $container) { $container->services() @@ -19,7 +19,7 @@ ->parent('cache.app') ->tag('cache.pool') - ->set('limiter', RateLimiter::class) + ->set('limiter', RateLimiterFactory::class) ->abstract() ->args([ abstract_arg('config'), diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index 5e08a445c9e15..31e3e35716df8 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -18,7 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\Security\Http\EventListener\LoginThrottlingListener; use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter; @@ -63,7 +63,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal throw new \LogicException('Login throttling requires symfony/security-http:^5.2.'); } - if (!class_exists(RateLimiter::class)) { + if (!class_exists(RateLimiterFactory::class)) { throw new \LogicException('Login throttling requires symfony/rate-limiter to be installed and enabled.'); } diff --git a/src/Symfony/Component/RateLimiter/README.md b/src/Symfony/Component/RateLimiter/README.md index 18e91b9e09f47..72fe4adf277f9 100644 --- a/src/Symfony/Component/RateLimiter/README.md +++ b/src/Symfony/Component/RateLimiter/README.md @@ -18,11 +18,11 @@ $ composer require symfony/rate-limiter ```php use Symfony\Component\RateLimiter\Storage\InMemoryStorage; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; -$limiter = new RateLimiter([ +$limiter = new RateLimiterFactory([ 'id' => 'login', - 'strategy' => 'token_bucket', // or 'fixed_window' + 'strategy' => 'token_bucket', 'limit' => 10, 'rate' => ['interval' => '15 minutes'], ], new InMemoryStorage()); diff --git a/src/Symfony/Component/RateLimiter/RateLimiter.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php similarity index 99% rename from src/Symfony/Component/RateLimiter/RateLimiter.php rename to src/Symfony/Component/RateLimiter/RateLimiterFactory.php index e7a177883ebc9..411b85d37502f 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiter.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -22,7 +22,7 @@ * * @experimental in 5.2 */ -final class RateLimiter +final class RateLimiterFactory { private $config; private $storage; diff --git a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php index c464e1a7e27c3..1cee3fd32a823 100644 --- a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Lock\LockFactory; use Symfony\Component\RateLimiter\FixedWindowLimiter; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\TokenBucketLimiter; @@ -61,6 +61,6 @@ public function testWrongInterval() private function createFactory(array $options) { - return new RateLimiter($options, $this->createMock(StorageInterface::class), $this->createMock(LockFactory::class)); + return new RateLimiterFactory($options, $this->createMock(StorageInterface::class), $this->createMock(LockFactory::class)); } } diff --git a/src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php similarity index 89% rename from src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php rename to src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php index 0c84ce33a9d38..9b3faa887996c 100644 --- a/src/Symfony/Component/RateLimiter/Tests/RateLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php @@ -15,19 +15,19 @@ use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; use Symfony\Component\RateLimiter\FixedWindowLimiter; use Symfony\Component\RateLimiter\NoLimiter; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\RateLimiter\SlidingWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\RateLimiter\TokenBucketLimiter; -class RateLimiterTest extends TestCase +class RateLimiterFactoryTest extends TestCase { /** * @dataProvider validConfigProvider */ public function testValidConfig(string $expectedClass, array $config) { - $factory = new RateLimiter($config, new InMemoryStorage()); + $factory = new RateLimiterFactory($config, new InMemoryStorage()); $rateLimiter = $factory->create('key'); $this->assertInstanceOf($expectedClass, $rateLimiter); } @@ -66,7 +66,7 @@ public function validConfigProvider() public function testInvalidConfig(string $exceptionClass, array $config) { $this->expectException($exceptionClass); - $factory = new RateLimiter($config, new InMemoryStorage()); + $factory = new RateLimiterFactory($config, new InMemoryStorage()); $factory->create('key'); } diff --git a/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php b/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php index f5b69674e78c6..5a63559f677f7 100644 --- a/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php +++ b/src/Symfony/Component/Security/Http/RateLimiter/DefaultLoginRateLimiter.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpFoundation\RateLimiter\AbstractRequestRateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\Security\Core\Security; /** @@ -28,20 +28,20 @@ */ final class DefaultLoginRateLimiter extends AbstractRequestRateLimiter { - private $globalLimiter; - private $localLimiter; + private $globalFactory; + private $localFactory; - public function __construct(RateLimiter $globalLimiter, RateLimiter $localLimiter) + public function __construct(RateLimiterFactory $globalFactory, RateLimiterFactory $localFactory) { - $this->globalLimiter = $globalLimiter; - $this->localLimiter = $localLimiter; + $this->globalFactory = $globalFactory; + $this->localFactory = $localFactory; } protected function getLimiters(Request $request): array { return [ - $this->globalLimiter->create($request->getClientIp()), - $this->localLimiter->create($request->attributes->get(Security::LAST_USERNAME).$request->getClientIp()), + $this->globalFactory->create($request->getClientIp()), + $this->localFactory->create($request->attributes->get(Security::LAST_USERNAME).$request->getClientIp()), ]; } } diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php index 4425afa8b058d..b19dbb9c58d52 100644 --- a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\RateLimiter\RateLimiter; +use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\TooManyLoginAttemptsAuthenticationException; @@ -35,13 +35,13 @@ protected function setUp(): void { $this->requestStack = new RequestStack(); - $localLimiter = new RateLimiter([ + $localLimiter = new RateLimiterFactory([ 'id' => 'login', 'strategy' => 'fixed_window', 'limit' => 3, 'interval' => '1 minute', ], new InMemoryStorage()); - $globalLimiter = new RateLimiter([ + $globalLimiter = new RateLimiterFactory([ 'id' => 'login', 'strategy' => 'fixed_window', 'limit' => 6, From 552e704d6c8bb8f50620a0402debc02e0b16a536 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 24 Oct 2020 10:12:34 +0200 Subject: [PATCH 072/146] [HttpClient] Adding missing dependency for dev --- src/Symfony/Component/HttpClient/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index b56827aae40f5..0961c46f2abae 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -39,7 +39,8 @@ "psr/http-client": "^1.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/http-kernel": "^4.4.13|^5.1.5", - "symfony/process": "^4.4|^5.0" + "symfony/process": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpClient\\": "" }, From f3976ee5d86e1ce7ba12fc4c3c09393368367511 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 24 Oct 2020 10:20:26 +0200 Subject: [PATCH 073/146] [PHPUnitBridge] Silence errors from mkdir() --- .../PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php index 403d23cdd5505..5c2f28264037b 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php @@ -41,7 +41,7 @@ private static function getVendorDir() } self::$vendorDir = $vendorDir; - mkdir($vendorDir.'/myfakevendor/myfakepackage2'); + @mkdir($vendorDir.'/myfakevendor/myfakepackage2'); touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php'); touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php'); touch($vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php'); From ac2059426795739365fc39e906bf1e4f0e1c353c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Oct 2020 15:00:49 +0200 Subject: [PATCH 074/146] [HttpClient] relax auth bearer format requirements --- src/Symfony/Component/HttpClient/HttpClientTrait.php | 9 +++++++-- .../Component/HttpClient/Tests/HttpClientTraitTest.php | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 26318309f0fc2..2431e806b033d 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -110,8 +110,13 @@ private static function prepareRequest(?string $method, ?string $url, array $opt throw new InvalidArgumentException(sprintf('Option "auth_basic" must be string or an array, "%s" given.', \gettype($options['auth_basic']))); } - if (isset($options['auth_bearer']) && (!\is_string($options['auth_bearer']) || !preg_match('{^[-._=:~+/0-9a-zA-Z]++$}', $options['auth_bearer']))) { - throw new InvalidArgumentException(sprintf('Option "auth_bearer" must be a string containing only characters from the base 64 alphabet, '.(\is_string($options['auth_bearer']) ? 'invalid string given.' : '"%s" given.'), \gettype($options['auth_bearer']))); + if (isset($options['auth_bearer'])) { + if (!\is_string($options['auth_bearer'])) { + throw new InvalidArgumentException(sprintf('Option "auth_bearer" must be a string, "%s" given.', \gettype($options['auth_bearer']))); + } + if (preg_match('{[^\x21-\x7E]}', $options['auth_bearer'])) { + throw new InvalidArgumentException('Invalid character found in option "auth_bearer": '.json_encode($options['auth_bearer']).'.'); + } } if (isset($options['auth_basic'], $options['auth_bearer'])) { diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index 477c33d924293..bce71ce823211 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -179,14 +179,14 @@ public function testAuthBearerOption() public function testInvalidAuthBearerOption() { $this->expectException('Symfony\Component\HttpClient\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Option "auth_bearer" must be a string containing only characters from the base 64 alphabet, "object" given.'); + $this->expectExceptionMessage('Option "auth_bearer" must be a string, "object" given.'); self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => new \stdClass()], HttpClientInterface::OPTIONS_DEFAULTS); } public function testInvalidAuthBearerValue() { $this->expectException('Symfony\Component\HttpClient\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Option "auth_bearer" must be a string containing only characters from the base 64 alphabet, invalid string given.'); + $this->expectExceptionMessage('Invalid character found in option "auth_bearer": "a\nb".'); self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => "a\nb"], HttpClientInterface::OPTIONS_DEFAULTS); } From f8fe4bf9f5c8203a70a2251510cafee66255c881 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 Oct 2020 12:23:57 +0200 Subject: [PATCH 075/146] Remove branch-version (keep them for contracts only) --- .appveyor.yml | 2 +- .github/build-packages.php | 9 +++------ .travis.yml | 13 ++++++------- composer.json | 5 +---- src/Symfony/Bridge/Doctrine/composer.json | 5 +---- src/Symfony/Bridge/Monolog/composer.json | 5 +---- src/Symfony/Bridge/PhpUnit/composer.json | 1 - src/Symfony/Bridge/ProxyManager/composer.json | 5 +---- src/Symfony/Bridge/Twig/composer.json | 5 +---- src/Symfony/Bundle/DebugBundle/composer.json | 5 +---- src/Symfony/Bundle/FrameworkBundle/composer.json | 5 +---- src/Symfony/Bundle/SecurityBundle/composer.json | 5 +---- src/Symfony/Bundle/TwigBundle/composer.json | 5 +---- src/Symfony/Bundle/WebProfilerBundle/composer.json | 5 +---- src/Symfony/Bundle/WebServerBundle/composer.json | 5 +---- src/Symfony/Component/Asset/composer.json | 5 +---- src/Symfony/Component/BrowserKit/composer.json | 5 +---- src/Symfony/Component/Cache/composer.json | 5 +---- src/Symfony/Component/ClassLoader/composer.json | 3 --- src/Symfony/Component/Config/composer.json | 5 +---- src/Symfony/Component/Console/composer.json | 5 +---- src/Symfony/Component/CssSelector/composer.json | 5 +---- src/Symfony/Component/Debug/composer.json | 5 +---- .../Component/DependencyInjection/composer.json | 5 +---- src/Symfony/Component/DomCrawler/composer.json | 5 +---- src/Symfony/Component/Dotenv/composer.json | 5 +---- src/Symfony/Component/EventDispatcher/composer.json | 5 +---- .../Component/ExpressionLanguage/composer.json | 5 +---- src/Symfony/Component/Filesystem/composer.json | 5 +---- src/Symfony/Component/Finder/composer.json | 5 +---- src/Symfony/Component/Form/composer.json | 5 +---- src/Symfony/Component/HttpFoundation/composer.json | 5 +---- src/Symfony/Component/HttpKernel/composer.json | 5 +---- src/Symfony/Component/Inflector/composer.json | 5 +---- src/Symfony/Component/Intl/composer.json | 5 +---- src/Symfony/Component/Ldap/composer.json | 5 +---- src/Symfony/Component/Lock/composer.json | 5 +---- src/Symfony/Component/OptionsResolver/composer.json | 5 +---- src/Symfony/Component/Process/composer.json | 5 +---- src/Symfony/Component/PropertyAccess/composer.json | 5 +---- src/Symfony/Component/PropertyInfo/composer.json | 5 +---- src/Symfony/Component/Routing/composer.json | 5 +---- src/Symfony/Component/Security/Core/composer.json | 5 +---- src/Symfony/Component/Security/Csrf/composer.json | 5 +---- src/Symfony/Component/Security/Guard/composer.json | 5 +---- src/Symfony/Component/Security/Http/composer.json | 5 +---- src/Symfony/Component/Security/composer.json | 5 +---- src/Symfony/Component/Serializer/composer.json | 5 +---- src/Symfony/Component/Stopwatch/composer.json | 5 +---- src/Symfony/Component/Templating/composer.json | 5 +---- src/Symfony/Component/Translation/composer.json | 5 +---- src/Symfony/Component/Validator/composer.json | 5 +---- src/Symfony/Component/VarDumper/composer.json | 5 +---- src/Symfony/Component/WebLink/composer.json | 5 +---- src/Symfony/Component/Workflow/composer.json | 5 +---- src/Symfony/Component/Yaml/composer.json | 5 +---- 56 files changed, 61 insertions(+), 222 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f9a43d84d65bf..1c1a693e12f36 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ install: - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex - git config --global user.email "" - git config --global user.name "Symfony" - - php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit + - php .github/build-packages.php "HEAD^" %APPVEYOR_REPO_BRANCH% src\Symfony\Bridge\PhpUnit - SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev - php composer.phar config platform.php 5.5.9 - php composer.phar update --no-progress --no-suggest --ansi diff --git a/.github/build-packages.php b/.github/build-packages.php index 8216f4d5124d6..13978ab4e6d93 100644 --- a/.github/build-packages.php +++ b/.github/build-packages.php @@ -1,7 +1,7 @@ $_SERVER['argc']) { - echo "Usage: branch dir1 dir2 ... dirN\n"; + echo "Usage: branch version dir1 dir2 ... dirN\n"; exit(1); } chdir(dirname(__DIR__)); @@ -14,6 +14,7 @@ $dirs = $_SERVER['argv']; array_shift($dirs); $mergeBase = trim(shell_exec(sprintf('git merge-base "%s" HEAD', array_shift($dirs)))); +$version = array_shift($dirs); $packages = array(); $flags = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; @@ -50,11 +51,7 @@ passthru("cd $dir && git init && git add . && git commit -q -m - && git archive -o package.tar HEAD && rm .git/ -Rf"); } - if (!isset($package->extra->{'branch-version'})) { - echo "Missing \"branch-version\" in composer.json's \"extra\".\n"; - exit(1); - } - $package->version = $package->extra->{'branch-version'}.'.x-dev'; + $package->version = (isset($package->extra->{'branch-version'}) ? $package->extra->{'branch-version'} : $version).'.x-dev'; $package->dist['type'] = 'tar'; $package->dist['url'] = 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__))."/$dir/package.tar"; diff --git a/.travis.yml b/.travis.yml index 71c306e3786b9..823b815c17c19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,6 @@ before_install: $HOME/.phpenv/versions/7.1/bin/php $HOME/.phpenv/versions/7.1/bin/composer $* } export -f composer - ~/.phpenv/versions/7.1/bin/composer self-update fi nanoseconds () { @@ -211,7 +210,7 @@ install: git fetch --depth=2 origin refs/pull/$SYMFONY_PHPUNIT_BRIDGE_PR/head git rm -rq src/Symfony/Bridge/PhpUnit git checkout -q FETCH_HEAD -- src/Symfony/Bridge/PhpUnit - export SYMFONY_VERSION=$(cat src/Symfony/Bridge/PhpUnit/composer.json | grep '^ *"branch-version". *"[1-9]' | grep -o '[0-9.]*') + export SYMFONY_VERSION=$(curl -s https://api.github.com/repos/symfony/symfony/pulls/$SYMFONY_PHPUNIT_BRIDGE_PR | jq -r .base.ref) sed -i 's/"symfony\/phpunit-bridge": ".*"/"symfony\/phpunit-bridge": "'$SYMFONY_VERSION'.x@dev"/' composer.json rm -rf .phpunit fi @@ -222,12 +221,12 @@ install: git config --global user.name "Symfony" if [[ ! $deps ]]; then - php .github/build-packages.php HEAD^ src/Symfony/Bridge/PhpUnit + php .github/build-packages.php HEAD^ $TRAVIS_BRANCH src/Symfony/Bridge/PhpUnit else export SYMFONY_DEPRECATIONS_HELPER=weak && cp composer.json composer.json.orig && echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json && - php .github/build-packages.php HEAD^ $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && + php .github/build-packages.php HEAD^ $TRAVIS_BRANCH $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && mv composer.json composer.json.phpunit && mv composer.json.orig composer.json fi @@ -240,12 +239,12 @@ install: # For the feature-branch, when deps=high, the version before it is checked out and tested with the locally patched components if [[ $deps = high && $TRAVIS_BRANCH = *.x ]]; then export FLIP='🙃' - export SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//) && + export SYMFONY_VERSION=$(git ls-remote -q --heads | grep -o '/[1-9]\.[0-9].*' | tail -n 1 | sed s/.//) && git fetch --depth=2 origin $SYMFONY_VERSION && git checkout -m FETCH_HEAD && export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n' | sort) else - export SYMFONY_VERSION=$(cat composer.json | grep '^ *"branch-version". *"[1-9]' | grep -o '[0-9.]*') + export SYMFONY_VERSION=$TRAVIS_BRANCH fi - | @@ -272,7 +271,7 @@ install: - | # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one - [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"branch-version". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]] && export LEGACY=,legacy + [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git ls-remote -q --heads | cut -f2 | grep -FA1 /$SYMFONY_VERSION | tail -n 1 | grep -o '[0-9]*') ]] && export LEGACY=,legacy export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev if [[ $deps ]]; then mv composer.json.phpunit composer.json; fi diff --git a/composer.json b/composer.json index 8fa2384bd6b39..0f0c8b48bcce2 100644 --- a/composer.json +++ b/composer.json @@ -133,8 +133,5 @@ "autoload-dev": { "files": [ "src/Symfony/Component/VarDumper/Resources/functions/dump.php" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 0aa807111843e..de304ddddba4f 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -56,8 +56,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index d17f61b5c078a..d76e263d1711c 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -42,8 +42,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index a9154a6e91ffd..3a3fbbdc15e3e 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -38,7 +38,6 @@ ], "minimum-stability": "dev", "extra": { - "branch-version": "3.4", "thanks": { "name": "phpunit/phpunit", "url": "https://github.com/sebastianbergmann/phpunit" diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 1c86bdec95078..09c390db09030 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -29,8 +29,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 17ee70aba70b6..f61e4018eb9a8 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -66,8 +66,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json index 177831731cd7c..cbdb1be64e419 100644 --- a/src/Symfony/Bundle/DebugBundle/composer.json +++ b/src/Symfony/Bundle/DebugBundle/composer.json @@ -40,8 +40,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 69e1737a65050..824bc8f07a503 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -90,8 +90,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 03ae6297cbf0d..01d49e222e282 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -61,8 +61,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 6ad8667faad8a..16c0888ef013c 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -50,8 +50,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index 6a6bdc9cd24c1..e956f6f42e68c 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -44,8 +44,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Bundle/WebServerBundle/composer.json b/src/Symfony/Bundle/WebServerBundle/composer.json index 573adc58e4128..8f2b7225d1b48 100644 --- a/src/Symfony/Bundle/WebServerBundle/composer.json +++ b/src/Symfony/Bundle/WebServerBundle/composer.json @@ -34,8 +34,5 @@ "symfony/monolog-bridge": "For using the log server.", "symfony/expression-language": "For using the filter option of the log server." }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Asset/composer.json b/src/Symfony/Component/Asset/composer.json index 430630f5c251f..0554c780704e8 100644 --- a/src/Symfony/Component/Asset/composer.json +++ b/src/Symfony/Component/Asset/composer.json @@ -31,8 +31,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/BrowserKit/composer.json b/src/Symfony/Component/BrowserKit/composer.json index 70b1c127eb7ea..25b06b18b5a03 100644 --- a/src/Symfony/Component/BrowserKit/composer.json +++ b/src/Symfony/Component/BrowserKit/composer.json @@ -32,8 +32,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 6a03c7d08f4c9..f412e4f170687 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -41,8 +41,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/ClassLoader/composer.json b/src/Symfony/Component/ClassLoader/composer.json index ffab1952a7303..667df14d18002 100644 --- a/src/Symfony/Component/ClassLoader/composer.json +++ b/src/Symfony/Component/ClassLoader/composer.json @@ -31,8 +31,5 @@ "exclude-from-classmap": [ "/Tests/" ] - }, - "extra": { - "branch-version": "3.4" } } diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index 43858bcb2bfb9..5088bdd832a84 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -39,8 +39,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 06b0b147124ad..298b99b66aba4 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -47,8 +47,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/CssSelector/composer.json b/src/Symfony/Component/CssSelector/composer.json index 5497961c195de..435063fd42dc4 100644 --- a/src/Symfony/Component/CssSelector/composer.json +++ b/src/Symfony/Component/CssSelector/composer.json @@ -28,8 +28,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Debug/composer.json b/src/Symfony/Component/Debug/composer.json index dd6a99b8c29f7..223d2bab36b49 100644 --- a/src/Symfony/Component/Debug/composer.json +++ b/src/Symfony/Component/Debug/composer.json @@ -31,8 +31,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index e5f130ea3d561..eee41ce0221ca 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -46,8 +46,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/DomCrawler/composer.json b/src/Symfony/Component/DomCrawler/composer.json index 72e4a7729319e..b4b17fc59bc23 100644 --- a/src/Symfony/Component/DomCrawler/composer.json +++ b/src/Symfony/Component/DomCrawler/composer.json @@ -32,8 +32,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Dotenv/composer.json b/src/Symfony/Component/Dotenv/composer.json index 9179325e4d127..be720a08edc4c 100644 --- a/src/Symfony/Component/Dotenv/composer.json +++ b/src/Symfony/Component/Dotenv/composer.json @@ -27,8 +27,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json index 2c7bd90d0bda1..408022f6bf3e4 100644 --- a/src/Symfony/Component/EventDispatcher/composer.json +++ b/src/Symfony/Component/EventDispatcher/composer.json @@ -39,8 +39,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index 3bb1c3d48e88a..5d5825b9af85c 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -26,8 +26,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Filesystem/composer.json b/src/Symfony/Component/Filesystem/composer.json index abea2324f1c8c..ee48b0b2385c0 100644 --- a/src/Symfony/Component/Filesystem/composer.json +++ b/src/Symfony/Component/Filesystem/composer.json @@ -25,8 +25,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Finder/composer.json b/src/Symfony/Component/Finder/composer.json index 066fa34bedb4c..b0895524be520 100644 --- a/src/Symfony/Component/Finder/composer.json +++ b/src/Symfony/Component/Finder/composer.json @@ -24,8 +24,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 5df6f2f33e303..945c76e46feee 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -57,8 +57,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/HttpFoundation/composer.json b/src/Symfony/Component/HttpFoundation/composer.json index adf40e95fa224..2f5ad1a31c99d 100644 --- a/src/Symfony/Component/HttpFoundation/composer.json +++ b/src/Symfony/Component/HttpFoundation/composer.json @@ -29,8 +29,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 94e77c6b36be6..06a67607ec917 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -65,8 +65,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Inflector/composer.json b/src/Symfony/Component/Inflector/composer.json index 4f9092712ce6a..db5d31dca211b 100644 --- a/src/Symfony/Component/Inflector/composer.json +++ b/src/Symfony/Component/Inflector/composer.json @@ -32,8 +32,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Intl/composer.json b/src/Symfony/Component/Intl/composer.json index 9eb80925a360e..640a8d7f599f7 100644 --- a/src/Symfony/Component/Intl/composer.json +++ b/src/Symfony/Component/Intl/composer.json @@ -40,8 +40,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Ldap/composer.json b/src/Symfony/Component/Ldap/composer.json index dacc28d73ced8..a61b57db7ce89 100644 --- a/src/Symfony/Component/Ldap/composer.json +++ b/src/Symfony/Component/Ldap/composer.json @@ -27,8 +27,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index c9ef82c06593b..5de7d680f2f65 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -29,8 +29,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/OptionsResolver/composer.json b/src/Symfony/Component/OptionsResolver/composer.json index 365ad20e4750f..0f7e1fd38e997 100644 --- a/src/Symfony/Component/OptionsResolver/composer.json +++ b/src/Symfony/Component/OptionsResolver/composer.json @@ -24,8 +24,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Process/composer.json b/src/Symfony/Component/Process/composer.json index cfc0b82fe61f7..f88f521410330 100644 --- a/src/Symfony/Component/Process/composer.json +++ b/src/Symfony/Component/Process/composer.json @@ -24,8 +24,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/PropertyAccess/composer.json b/src/Symfony/Component/PropertyAccess/composer.json index 8950cdab0dd3a..825ef62b8e3e3 100644 --- a/src/Symfony/Component/PropertyAccess/composer.json +++ b/src/Symfony/Component/PropertyAccess/composer.json @@ -32,8 +32,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index 6757add10d78a..972e58cb7e5fe 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -50,8 +50,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json index 5eb4372289165..2c686ba739fcf 100644 --- a/src/Symfony/Component/Routing/composer.json +++ b/src/Symfony/Component/Routing/composer.json @@ -45,8 +45,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index 76883926dbd4e..608e99c19eab2 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -42,8 +42,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Security/Csrf/composer.json b/src/Symfony/Component/Security/Csrf/composer.json index a816ac49391df..a76561510d51c 100644 --- a/src/Symfony/Component/Security/Csrf/composer.json +++ b/src/Symfony/Component/Security/Csrf/composer.json @@ -36,8 +36,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Security/Guard/composer.json b/src/Symfony/Component/Security/Guard/composer.json index 32b0395a4b651..69fc3601b0bdf 100644 --- a/src/Symfony/Component/Security/Guard/composer.json +++ b/src/Symfony/Component/Security/Guard/composer.json @@ -29,8 +29,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index 1af37b88b961c..7db0b20a69197 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -43,8 +43,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index f715c29322012..8f5b26db57873 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -58,8 +58,5 @@ "/Http/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index 9f766f5ebf0a3..c6154343a9ebe 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -54,8 +54,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Stopwatch/composer.json b/src/Symfony/Component/Stopwatch/composer.json index 2dcd1db02210d..9fdd55e917a5a 100644 --- a/src/Symfony/Component/Stopwatch/composer.json +++ b/src/Symfony/Component/Stopwatch/composer.json @@ -24,8 +24,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Templating/composer.json b/src/Symfony/Component/Templating/composer.json index c5f4715a0a85b..17540fdc1af5d 100644 --- a/src/Symfony/Component/Templating/composer.json +++ b/src/Symfony/Component/Templating/composer.json @@ -31,8 +31,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Translation/composer.json b/src/Symfony/Component/Translation/composer.json index 2255a6a755ed7..115d0795066e4 100644 --- a/src/Symfony/Component/Translation/composer.json +++ b/src/Symfony/Component/Translation/composer.json @@ -45,8 +45,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 841798089631d..0050343fa9544 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -61,8 +61,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/VarDumper/composer.json b/src/Symfony/Component/VarDumper/composer.json index 2a2ff2d89f9ce..9f2352ee2569c 100644 --- a/src/Symfony/Component/VarDumper/composer.json +++ b/src/Symfony/Component/VarDumper/composer.json @@ -38,8 +38,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/WebLink/composer.json b/src/Symfony/Component/WebLink/composer.json index 381e83fbf490a..19d9960133053 100644 --- a/src/Symfony/Component/WebLink/composer.json +++ b/src/Symfony/Component/WebLink/composer.json @@ -34,8 +34,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Workflow/composer.json b/src/Symfony/Component/Workflow/composer.json index 4c1e255e05c1d..510d19f86240c 100644 --- a/src/Symfony/Component/Workflow/composer.json +++ b/src/Symfony/Component/Workflow/composer.json @@ -34,8 +34,5 @@ "autoload": { "psr-4": { "Symfony\\Component\\Workflow\\": "" } }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } diff --git a/src/Symfony/Component/Yaml/composer.json b/src/Symfony/Component/Yaml/composer.json index cccdfcb37b4d2..b2f0286e0eab9 100644 --- a/src/Symfony/Component/Yaml/composer.json +++ b/src/Symfony/Component/Yaml/composer.json @@ -34,8 +34,5 @@ "/Tests/" ] }, - "minimum-stability": "dev", - "extra": { - "branch-version": "3.4" - } + "minimum-stability": "dev" } From 2c4dff8461f0265528c8082b73ee20089e7ae4bb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 Oct 2020 13:56:22 +0200 Subject: [PATCH 076/146] fix merge --- src/Symfony/Bridge/PhpUnit/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 951684acb302e..85318fe178e58 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -37,6 +37,7 @@ "bin/simple-phpunit" ], "minimum-stability": "dev", + "extra": { "thanks": { "name": "phpunit/phpunit", "url": "https://github.com/sebastianbergmann/phpunit" From 60e969e01eb2307cf581c78b070e41cc2a14ce46 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 Oct 2020 14:03:25 +0200 Subject: [PATCH 077/146] fix merge --- src/Symfony/Component/Notifier/composer.json | 4 ---- src/Symfony/Component/Yaml/composer.json | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/Symfony/Component/Notifier/composer.json b/src/Symfony/Component/Notifier/composer.json index 4a5cb199aa4bc..f56ff3d662053 100644 --- a/src/Symfony/Component/Notifier/composer.json +++ b/src/Symfony/Component/Notifier/composer.json @@ -28,9 +28,5 @@ "/Tests/" ] }, -<<<<<<< HEAD:src/Symfony/Component/Notifier/composer.json "minimum-stability": "dev" -======= - "minimum-stability": "dev" ->>>>>>> 4.4:src/Symfony/Component/Debug/composer.json } diff --git a/src/Symfony/Component/Yaml/composer.json b/src/Symfony/Component/Yaml/composer.json index 79d5f92a94eab..a8b8134bcfa44 100644 --- a/src/Symfony/Component/Yaml/composer.json +++ b/src/Symfony/Component/Yaml/composer.json @@ -35,12 +35,8 @@ "/Tests/" ] }, -<<<<<<< HEAD "bin": [ "Resources/bin/yaml-lint" ], "minimum-stability": "dev" -======= - "minimum-stability": "dev" ->>>>>>> 4.4 } From 9f322091c8cd35b706b80ee9ab871bb23aa320b7 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 24 Oct 2020 14:31:07 +0200 Subject: [PATCH 078/146] Bump default PHPUnit version for PHP 8 to 9.4. --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 00c99a18ecad7..08be74fc721a8 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -95,7 +95,7 @@ if (\PHP_VERSION_ID >= 80000) { // PHP 8 requires PHPUnit 9.3+ - $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.3'); + $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.4'); } elseif (\PHP_VERSION_ID >= 70200) { // PHPUnit 8 requires PHP 7.2+ $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.3'); @@ -196,7 +196,7 @@ 'requires' => ['php' => '*'], ]; - $stableVersions = array_filter($info['versions'], function($v) { + $stableVersions = array_filter($info['versions'], function ($v) { return !preg_match('/-dev$|^dev-/', $v); }); From 008f2da03167fb256056549b3d8c994535bb8c17 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 Oct 2020 14:44:01 +0200 Subject: [PATCH 079/146] Put branch-version in the source for CI --- .appveyor.yml | 18 +++++++++++------- .travis.yml | 16 +++++++++------- composer.json | 5 ++++- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 1c1a693e12f36..86ed50c856b37 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,7 +10,6 @@ init: - SET PATH=c:\php;%PATH% - SET COMPOSER_NO_INTERACTION=1 - SET SYMFONY_DEPRECATIONS_HELPER=strict - - SET "SYMFONY_REQUIRE=>=3.4" - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_VERSION=4.8 - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 @@ -49,18 +48,23 @@ install: - echo curl.cainfo=c:\php\cacert.pem >> php.ini-max - copy /Y php.ini-min php.ini - echo extension=php_openssl.dll >> php.ini + - echo extension=php_curl.dll >> php.ini + - echo curl.cainfo=c:\php\cacert.pem >> php.ini - cd c:\projects\symfony - - IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/1.9.0/composer.phar) - - php composer.phar self-update + - IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/2.0.0/composer.phar) + - php composer.phar self-update --2 - copy /Y .github\composer-config.json %APPDATA%\Composer\config.json - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex - git config --global user.email "" - git config --global user.name "Symfony" - - php .github/build-packages.php "HEAD^" %APPVEYOR_REPO_BRANCH% src\Symfony\Bridge\PhpUnit - - SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev - - php composer.phar config platform.php 5.5.9 - - php composer.phar update --no-progress --no-suggest --ansi + - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep branch-version composer.json | grep -o '[0-9.]*'"`) DO (SET SYMFONY_VERSION=%%F) + - php .github/build-packages.php "HEAD^" %SYMFONY_VERSION% src\Symfony\Bridge\PhpUnit + - SET "SYMFONY_REQUIRE=>=%SYMFONY_VERSION%" + - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev + - php composer.phar config --global platform.php 5.5.9 + - php composer.phar update --no-progress --ansi - php phpunit install + - break > .phpunit/phpunit-4.8-0/vendor/composer/platform_check.php test_script: - SET X=0 diff --git a/.travis.yml b/.travis.yml index 823b815c17c19..2675fe5f9c2bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,8 +75,8 @@ before_install: cp .github/composer-config.json ~/.composer/config.json export PHPUNIT=$(readlink -f ./phpunit) export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" - export COMPOSER_UP='composer update --no-progress --no-suggest --ansi' - export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n' | sort) + export COMPOSER_UP='composer update --no-progress --ansi' + export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) find ~/.phpenv -name xdebug.ini -delete if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then @@ -220,13 +220,15 @@ install: git config --global user.email "" git config --global user.name "Symfony" + export SYMFONY_VERSION=$(grep branch-version composer.json | grep -o '[0-9.]*') + if [[ ! $deps ]]; then - php .github/build-packages.php HEAD^ $TRAVIS_BRANCH src/Symfony/Bridge/PhpUnit + php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit else export SYMFONY_DEPRECATIONS_HELPER=weak && cp composer.json composer.json.orig && echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json && - php .github/build-packages.php HEAD^ $TRAVIS_BRANCH $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && + php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && mv composer.json composer.json.phpunit && mv composer.json.orig composer.json fi @@ -242,9 +244,7 @@ install: export SYMFONY_VERSION=$(git ls-remote -q --heads | grep -o '/[1-9]\.[0-9].*' | tail -n 1 | sed s/.//) && git fetch --depth=2 origin $SYMFONY_VERSION && git checkout -m FETCH_HEAD && - export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n' | sort) - else - export SYMFONY_VERSION=$TRAVIS_BRANCH + export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) fi - | @@ -289,6 +289,7 @@ install: return fi phpenv global ${PHP/hhvm*/hhvm} + rm vendor/composer/package-versions-deprecated -Rf if [[ $PHP = 7.* ]]; then ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.6.0; composer require --dev --no-update mongodb/mongodb ~1.5.0) fi @@ -311,6 +312,7 @@ install: tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty if [[ $PHP = ${MIN_PHP%.*} ]]; then export PHP=$MIN_PHP + echo '' > vendor/composer/platform_check.php echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} SYMFONY_DEPRECATIONS_HELPER=weak ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8-1/phpunit --colors=always src/Symfony/Component/Process/" fi fi diff --git a/composer.json b/composer.json index 0f0c8b48bcce2..8fa2384bd6b39 100644 --- a/composer.json +++ b/composer.json @@ -133,5 +133,8 @@ "autoload-dev": { "files": [ "src/Symfony/Component/VarDumper/Resources/functions/dump.php" ] }, - "minimum-stability": "dev" + "minimum-stability": "dev", + "extra": { + "branch-version": "3.4" + } } From 46b0d66470aa828b121e670d56a169d15a31a5d9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 Oct 2020 14:44:01 +0200 Subject: [PATCH 080/146] Disable platform checks --- .github/workflows/tests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9b06d7e55531b..1c5e5e7000cbc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -52,13 +52,11 @@ jobs: extensions: "memcached,redis,xsl" ini-values: "memory_limit=-1" php-version: "${{ matrix.php }}" - tools: flex - name: Configure composer run: | ([ -d ~/.composer ] || mkdir ~/.composer) && cp .github/composer-config.json ~/.composer/config.json - BRANCH_REF=${GITHUB_BASE_REF:-$GITHUB_REF} - echo "COMPOSER_ROOT_VERSION=${BRANCH_REF:11}.x-dev" >> $GITHUB_ENV + echo "COMPOSER_ROOT_VERSION=$(grep branch-version composer.json | grep -o '[0-9.]*').x-dev" >> $GITHUB_ENV - name: Determine composer cache directory id: composer-cache @@ -93,6 +91,7 @@ jobs: if: matrix.php == '7.4' run: | [ -d .phpunit ] && mv .phpunit .phpunit.bak + echo '' > vendor/composer/platform_check.php wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz -O - | tar xz && mv vulcain /usr/local/bin docker run --rm -e COMPOSER_ROOT_VERSION -v $(pwd):/app -v $(which composer):/usr/local/bin/composer -v /usr/local/bin/vulcain:/usr/local/bin/vulcain -w /app php:7.4-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push sudo rm -rf .phpunit From e17797c8e48e94200c07306f28e08fb296d65f37 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 24 Oct 2020 23:50:04 +0200 Subject: [PATCH 081/146] [Cache] Fixed broken test --- src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php index b2905297ebe7d..36bf3c4a39f5b 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -38,7 +38,7 @@ public function createCachePool(int $defaultLifetime = 0, string $testMethod = n public static function tearDownAfterClass(): void { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); + (new Filesystem())->remove(sys_get_temp_dir().'/symfony-cache'); } public function testEmptyAdaptersException() From 1e6cea56e476acf19a039f701734eeb4309f8a9c Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Oct 2020 23:15:23 +0200 Subject: [PATCH 082/146] [RateLimiter] Moved classes implementing LimiterInterface to a new namespace --- .../DependencyInjection/Configuration.php | 8 ++++---- .../Factory/LoginThrottlingFactory.php | 2 +- .../RateLimiter/AbstractRequestRateLimiter.php | 2 +- .../{ => Policy}/FixedWindowLimiter.php | 5 ++++- .../RateLimiter/{ => Policy}/NoLimiter.php | 6 +++++- .../RateLimiter/{ => Policy}/Rate.php | 2 +- .../{ => Policy}/ResetLimiterTrait.php | 2 +- .../RateLimiter/{ => Policy}/SlidingWindow.php | 3 ++- .../{ => Policy}/SlidingWindowLimiter.php | 5 ++++- .../RateLimiter/{ => Policy}/TokenBucket.php | 4 +++- .../{ => Policy}/TokenBucketLimiter.php | 5 ++++- .../RateLimiter/{ => Policy}/Window.php | 4 +++- src/Symfony/Component/RateLimiter/README.md | 2 +- .../RateLimiter/RateLimiterFactory.php | 11 ++++++++--- .../RateLimiter/Tests/CompoundLimiterTest.php | 2 +- .../RateLimiter/Tests/LimiterTest.php | 10 +++++----- .../Tests/RateLimiterFactoryTest.php | 18 +++++++++--------- .../Tests/Storage/CacheStorageTest.php | 2 +- .../{ => Strategy}/FixedWindowLimiterTest.php | 4 ++-- .../SlidingWindowLimiterTest.php | 4 ++-- .../Tests/{ => Strategy}/SlidingWindowTest.php | 4 ++-- .../{ => Strategy}/TokenBucketLimiterTest.php | 8 ++++---- .../LoginThrottlingListenerTest.php | 4 ++-- 23 files changed, 70 insertions(+), 47 deletions(-) rename src/Symfony/Component/RateLimiter/{ => Policy}/FixedWindowLimiter.php (95%) rename src/Symfony/Component/RateLimiter/{ => Policy}/NoLimiter.php (82%) rename src/Symfony/Component/RateLimiter/{ => Policy}/Rate.php (98%) rename src/Symfony/Component/RateLimiter/{ => Policy}/ResetLimiterTrait.php (94%) rename src/Symfony/Component/RateLimiter/{ => Policy}/SlidingWindow.php (96%) rename src/Symfony/Component/RateLimiter/{ => Policy}/SlidingWindowLimiter.php (93%) rename src/Symfony/Component/RateLimiter/{ => Policy}/TokenBucket.php (95%) rename src/Symfony/Component/RateLimiter/{ => Policy}/TokenBucketLimiter.php (95%) rename src/Symfony/Component/RateLimiter/{ => Policy}/Window.php (95%) rename src/Symfony/Component/RateLimiter/Tests/{ => Strategy}/FixedWindowLimiterTest.php (95%) rename src/Symfony/Component/RateLimiter/Tests/{ => Strategy}/SlidingWindowLimiterTest.php (93%) rename src/Symfony/Component/RateLimiter/Tests/{ => Strategy}/SlidingWindowTest.php (90%) rename src/Symfony/Component/RateLimiter/Tests/{ => Strategy}/TokenBucketLimiterTest.php (94%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index a134940add3b7..717495d053744 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -31,7 +31,7 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Notifier\Notifier; use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; -use Symfony\Component\RateLimiter\TokenBucketLimiter; +use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Translation\Translator; use Symfony\Component\Validator\Validation; @@ -1843,7 +1843,7 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode) ->info('The service ID of a custom storage implementation, this precedes any configured "cache_pool"') ->defaultNull() ->end() - ->enumNode('strategy') + ->enumNode('policy') ->info('The rate limiting algorithm to use for this rate') ->isRequired() ->values(['fixed_window', 'token_bucket', 'sliding_window', 'no_limit']) @@ -1853,10 +1853,10 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode) ->isRequired() ->end() ->scalarNode('interval') - ->info('Configures the fixed interval if "strategy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).') + ->info('Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).') ->end() ->arrayNode('rate') - ->info('Configures the fill rate if "strategy" is set to "token_bucket"') + ->info('Configures the fill rate if "policy" is set to "token_bucket"') ->children() ->scalarNode('interval') ->info('Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).') diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index 31e3e35716df8..c0aa37ec88712 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -73,7 +73,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal } $limiterOptions = [ - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'limit' => $config['max_attempts'], 'interval' => '1 minute', ]; diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php index f700ebcd8657c..ddcdf6ca035a4 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\RateLimiter\LimiterInterface; -use Symfony\Component\RateLimiter\NoLimiter; +use Symfony\Component\RateLimiter\Policy\NoLimiter; use Symfony\Component\RateLimiter\RateLimit; /** diff --git a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php b/src/Symfony/Component/RateLimiter/Policy/FixedWindowLimiter.php similarity index 95% rename from src/Symfony/Component/RateLimiter/FixedWindowLimiter.php rename to src/Symfony/Component/RateLimiter/Policy/FixedWindowLimiter.php index fc44391f16c59..b5dfec19311a8 100644 --- a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/FixedWindowLimiter.php @@ -9,11 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\NoLock; use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException; +use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\RateLimit; +use Symfony\Component\RateLimiter\Reservation; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\Util\TimeUtil; diff --git a/src/Symfony/Component/RateLimiter/NoLimiter.php b/src/Symfony/Component/RateLimiter/Policy/NoLimiter.php similarity index 82% rename from src/Symfony/Component/RateLimiter/NoLimiter.php rename to src/Symfony/Component/RateLimiter/Policy/NoLimiter.php index 13ccbf10b6c0e..03d4e54331db2 100644 --- a/src/Symfony/Component/RateLimiter/NoLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/NoLimiter.php @@ -9,7 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; + +use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\RateLimit; +use Symfony\Component\RateLimiter\Reservation; /** * Implements a non limiting limiter. diff --git a/src/Symfony/Component/RateLimiter/Rate.php b/src/Symfony/Component/RateLimiter/Policy/Rate.php similarity index 98% rename from src/Symfony/Component/RateLimiter/Rate.php rename to src/Symfony/Component/RateLimiter/Policy/Rate.php index 009311e61262b..a0e89fb5c2deb 100644 --- a/src/Symfony/Component/RateLimiter/Rate.php +++ b/src/Symfony/Component/RateLimiter/Policy/Rate.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\RateLimiter\Util\TimeUtil; diff --git a/src/Symfony/Component/RateLimiter/ResetLimiterTrait.php b/src/Symfony/Component/RateLimiter/Policy/ResetLimiterTrait.php similarity index 94% rename from src/Symfony/Component/RateLimiter/ResetLimiterTrait.php rename to src/Symfony/Component/RateLimiter/Policy/ResetLimiterTrait.php index 2969bc0d5f304..a356490488669 100644 --- a/src/Symfony/Component/RateLimiter/ResetLimiterTrait.php +++ b/src/Symfony/Component/RateLimiter/Policy/ResetLimiterTrait.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\Lock\LockInterface; use Symfony\Component\RateLimiter\Storage\StorageInterface; diff --git a/src/Symfony/Component/RateLimiter/SlidingWindow.php b/src/Symfony/Component/RateLimiter/Policy/SlidingWindow.php similarity index 96% rename from src/Symfony/Component/RateLimiter/SlidingWindow.php rename to src/Symfony/Component/RateLimiter/Policy/SlidingWindow.php index 2b584d9c34aee..4188cf4ca3262 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindow.php +++ b/src/Symfony/Component/RateLimiter/Policy/SlidingWindow.php @@ -9,9 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\RateLimiter\Exception\InvalidIntervalException; +use Symfony\Component\RateLimiter\LimiterStateInterface; /** * @author Tobias Nyholm diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/Policy/SlidingWindowLimiter.php similarity index 93% rename from src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php rename to src/Symfony/Component/RateLimiter/Policy/SlidingWindowLimiter.php index f9d2ccac6d746..fe6f1da8c31f3 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/SlidingWindowLimiter.php @@ -9,11 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\NoLock; use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; +use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\RateLimit; +use Symfony\Component\RateLimiter\Reservation; use Symfony\Component\RateLimiter\Storage\StorageInterface; use Symfony\Component\RateLimiter\Util\TimeUtil; diff --git a/src/Symfony/Component/RateLimiter/TokenBucket.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php similarity index 95% rename from src/Symfony/Component/RateLimiter/TokenBucket.php rename to src/Symfony/Component/RateLimiter/Policy/TokenBucket.php index de5e52a32fc13..8464acf149777 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php @@ -9,7 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; + +use Symfony\Component\RateLimiter\LimiterStateInterface; /** * @author Wouter de Jong diff --git a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php similarity index 95% rename from src/Symfony/Component/RateLimiter/TokenBucketLimiter.php rename to src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php index 0d04763b46093..24f82d21ec720 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php @@ -9,11 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\NoLock; use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException; +use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\RateLimit; +use Symfony\Component\RateLimiter\Reservation; use Symfony\Component\RateLimiter\Storage\StorageInterface; /** diff --git a/src/Symfony/Component/RateLimiter/Window.php b/src/Symfony/Component/RateLimiter/Policy/Window.php similarity index 95% rename from src/Symfony/Component/RateLimiter/Window.php rename to src/Symfony/Component/RateLimiter/Policy/Window.php index 5720008f9b7c0..1cfd49eb82ffa 100644 --- a/src/Symfony/Component/RateLimiter/Window.php +++ b/src/Symfony/Component/RateLimiter/Policy/Window.php @@ -9,7 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter; +namespace Symfony\Component\RateLimiter\Policy; + +use Symfony\Component\RateLimiter\LimiterStateInterface; /** * @author Wouter de Jong diff --git a/src/Symfony/Component/RateLimiter/README.md b/src/Symfony/Component/RateLimiter/README.md index 72fe4adf277f9..9f8020a198947 100644 --- a/src/Symfony/Component/RateLimiter/README.md +++ b/src/Symfony/Component/RateLimiter/README.md @@ -22,7 +22,7 @@ use Symfony\Component\RateLimiter\RateLimiterFactory; $limiter = new RateLimiterFactory([ 'id' => 'login', - 'strategy' => 'token_bucket', + 'policy' => 'token_bucket', 'limit' => 10, 'rate' => ['interval' => '15 minutes'], ], new InMemoryStorage()); diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php index 411b85d37502f..9fdbe474bf3ef 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -15,6 +15,11 @@ use Symfony\Component\Lock\NoLock; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\NoLimiter; +use Symfony\Component\RateLimiter\Policy\Rate; +use Symfony\Component\RateLimiter\Policy\SlidingWindowLimiter; +use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter; use Symfony\Component\RateLimiter\Storage\StorageInterface; /** @@ -44,7 +49,7 @@ public function create(?string $key = null): LimiterInterface $id = $this->config['id'].$key; $lock = $this->lockFactory ? $this->lockFactory->createLock($id) : new NoLock(); - switch ($this->config['strategy']) { + switch ($this->config['policy']) { case 'token_bucket': return new TokenBucketLimiter($id, $this->config['limit'], $this->config['rate'], $this->storage, $lock); @@ -58,7 +63,7 @@ public function create(?string $key = null): LimiterInterface return new NoLimiter(); default: - throw new \LogicException(sprintf('Limiter strategy "%s" does not exists, it must be either "token_bucket", "sliding_window", "fixed_window" or "no_limit".', $this->config['strategy'])); + throw new \LogicException(sprintf('Limiter policy "%s" does not exists, it must be either "token_bucket", "sliding_window", "fixed_window" or "no_limit".', $this->config['policy'])); } } @@ -78,7 +83,7 @@ protected static function configureOptions(OptionsResolver $options): void $options ->define('id')->required() - ->define('strategy') + ->define('policy') ->required() ->allowedValues('token_bucket', 'fixed_window', 'sliding_window', 'no_limit') diff --git a/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php index fb28996f2069a..29a91eb182546 100644 --- a/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/CompoundLimiterTest.php @@ -15,7 +15,7 @@ use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Component\RateLimiter\CompoundLimiter; use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; -use Symfony\Component\RateLimiter\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; /** diff --git a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php index 1cee3fd32a823..cc6822dcdbaef 100644 --- a/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/LimiterTest.php @@ -13,10 +13,10 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Lock\LockFactory; -use Symfony\Component\RateLimiter\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter; use Symfony\Component\RateLimiter\RateLimiterFactory; use Symfony\Component\RateLimiter\Storage\StorageInterface; -use Symfony\Component\RateLimiter\TokenBucketLimiter; class LimiterTest extends TestCase { @@ -24,7 +24,7 @@ public function testTokenBucket() { $factory = $this->createFactory([ 'id' => 'test', - 'strategy' => 'token_bucket', + 'policy' => 'token_bucket', 'limit' => 10, 'rate' => ['interval' => '1 second'], ]); @@ -37,7 +37,7 @@ public function testFixedWindow() { $factory = $this->createFactory([ 'id' => 'test', - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'limit' => 10, 'interval' => '1 minute', ]); @@ -53,7 +53,7 @@ public function testWrongInterval() $this->createFactory([ 'id' => 'test', - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'limit' => 10, 'interval' => '1 minut', ]); diff --git a/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php index 9b3faa887996c..7d7627809238e 100644 --- a/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php @@ -13,12 +13,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; -use Symfony\Component\RateLimiter\FixedWindowLimiter; -use Symfony\Component\RateLimiter\NoLimiter; +use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\NoLimiter; +use Symfony\Component\RateLimiter\Policy\SlidingWindowLimiter; +use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter; use Symfony\Component\RateLimiter\RateLimiterFactory; -use Symfony\Component\RateLimiter\SlidingWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; -use Symfony\Component\RateLimiter\TokenBucketLimiter; class RateLimiterFactoryTest extends TestCase { @@ -35,7 +35,7 @@ public function testValidConfig(string $expectedClass, array $config) public function validConfigProvider() { yield [TokenBucketLimiter::class, [ - 'strategy' => 'token_bucket', + 'policy' => 'token_bucket', 'id' => 'test', 'limit' => 5, 'rate' => [ @@ -43,19 +43,19 @@ public function validConfigProvider() ], ]]; yield [FixedWindowLimiter::class, [ - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'id' => 'test', 'limit' => 5, 'interval' => '5 seconds', ]]; yield [SlidingWindowLimiter::class, [ - 'strategy' => 'sliding_window', + 'policy' => 'sliding_window', 'id' => 'test', 'limit' => 5, 'interval' => '5 seconds', ]]; yield [NoLimiter::class, [ - 'strategy' => 'no_limit', + 'policy' => 'no_limit', 'id' => 'test', ]]; } @@ -73,7 +73,7 @@ public function testInvalidConfig(string $exceptionClass, array $config) public function invalidConfigProvider() { yield [MissingOptionsException::class, [ - 'strategy' => 'token_bucket', + 'policy' => 'token_bucket', ]]; } } diff --git a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php index 70f9246e37436..c1a11c556b6e3 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Storage/CacheStorageTest.php @@ -14,8 +14,8 @@ use PHPUnit\Framework\TestCase; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\RateLimiter\Policy\Window; use Symfony\Component\RateLimiter\Storage\CacheStorage; -use Symfony\Component\RateLimiter\Window; class CacheStorageTest extends TestCase { diff --git a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Strategy/FixedWindowLimiterTest.php similarity index 95% rename from src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php rename to src/Symfony/Component/RateLimiter/Tests/Strategy/FixedWindowLimiterTest.php index 8ae6dcc875c24..137f6ccb92348 100644 --- a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Strategy/FixedWindowLimiterTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter\Tests; +namespace Symfony\Component\RateLimiter\Tests\Policy; use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ClockMock; -use Symfony\Component\RateLimiter\FixedWindowLimiter; +use Symfony\Component\RateLimiter\Policy\FixedWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\RateLimiter\Tests\Resources\DummyWindow; diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowLimiterTest.php similarity index 93% rename from src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php rename to src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowLimiterTest.php index 07146c765d6d0..2b34aeb1976fb 100644 --- a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowLimiterTest.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter\Tests; +namespace Symfony\Component\RateLimiter\Tests\Policy; use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException; -use Symfony\Component\RateLimiter\SlidingWindowLimiter; +use Symfony\Component\RateLimiter\Policy\SlidingWindowLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; /** diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php b/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowTest.php similarity index 90% rename from src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php rename to src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowTest.php index 0bdeb499c51b5..e0d29bcc128b1 100644 --- a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Strategy/SlidingWindowTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter\Tests; +namespace Symfony\Component\RateLimiter\Tests\Policy; use PHPUnit\Framework\TestCase; use Symfony\Component\RateLimiter\Exception\InvalidIntervalException; -use Symfony\Component\RateLimiter\SlidingWindow; +use Symfony\Component\RateLimiter\Policy\SlidingWindow; class SlidingWindowTest extends TestCase { diff --git a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Strategy/TokenBucketLimiterTest.php similarity index 94% rename from src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php rename to src/Symfony/Component/RateLimiter/Tests/Strategy/TokenBucketLimiterTest.php index b5b83649e20d9..09940dbdd2948 100644 --- a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Strategy/TokenBucketLimiterTest.php @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\RateLimiter\Tests; +namespace Symfony\Component\RateLimiter\Tests\Policy; use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException; -use Symfony\Component\RateLimiter\Rate; +use Symfony\Component\RateLimiter\Policy\Rate; +use Symfony\Component\RateLimiter\Policy\TokenBucket; +use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter; use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\RateLimiter\Tests\Resources\DummyWindow; -use Symfony\Component\RateLimiter\TokenBucket; -use Symfony\Component\RateLimiter\TokenBucketLimiter; /** * @group time-sensitive diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php index b19dbb9c58d52..1374fc39b0a4a 100644 --- a/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EventListener/LoginThrottlingListenerTest.php @@ -37,13 +37,13 @@ protected function setUp(): void $localLimiter = new RateLimiterFactory([ 'id' => 'login', - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'limit' => 3, 'interval' => '1 minute', ], new InMemoryStorage()); $globalLimiter = new RateLimiterFactory([ 'id' => 'login', - 'strategy' => 'fixed_window', + 'policy' => 'fixed_window', 'limit' => 6, 'interval' => '1 minute', ], new InMemoryStorage()); From 23fa42267ed7c73cd9efa9f1aa50b798656b72ff Mon Sep 17 00:00:00 2001 From: Marcin Michalski Date: Sun, 25 Oct 2020 11:11:03 +0100 Subject: [PATCH 083/146] [Security] Add missing polish translations --- .../Security/Core/Resources/translations/security.pl.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.pl.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.pl.xlf index 8d563d21206a9..2a24524b92665 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.pl.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.pl.xlf @@ -66,6 +66,14 @@ Account is locked. Konto jest zablokowane. + + Too many failed login attempts, please try again later. + Zbyt dużo nieudanych prób logowania, proszę spróbować ponownie później. + + + Invalid or expired login link. + Nieprawidłowy lub wygasły link logowania. + From ec3b0edc1f4414f27c3eaf0379fd2f7470929d40 Mon Sep 17 00:00:00 2001 From: Marcin Michalski Date: Sun, 25 Oct 2020 11:59:05 +0100 Subject: [PATCH 084/146] [Form] Add missing polish translations --- .../Resources/translations/validators.pl.xlf | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf index 64def2a69135c..d553f2a179a97 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. Token CSRF jest nieprawidłowy. Proszę spróbować wysłać formularz ponownie. + + This value is not a valid HTML5 color. + Ta wartość nie jest prawidłowym kolorem HTML5. + + + Please enter a valid birthdate. + Proszę wprowadzić prawidłową datę urodzenia. + + + The selected choice is invalid. + Wybrana wartość jest nieprawidłowa. + + + The collection is invalid. + Zbiór jest nieprawidłowy. + + + Please select a valid color. + Proszę wybrać prawidłowy kolor. + + + Please select a valid country. + Proszę wybrać prawidłowy kraj. + + + Please select a valid currency. + Proszę wybrać prawidłową walutę. + + + Please choose a valid date interval. + Proszę wybrać prawidłowy przedział czasowy. + + + Please enter a valid date and time. + Proszę wprowadzić prawidłową datę i czas. + + + Please enter a valid date. + Proszę wprowadzić prawidłową datę. + + + Please select a valid file. + Proszę wybrać prawidłowy plik. + + + The hidden field is invalid. + Ukryte pole jest nieprawidłowe. + + + Please enter an integer. + Proszę wprowadzić liczbę całkowitą. + + + Please select a valid language. + Proszę wybrać prawidłowy język. + + + Please select a valid locale. + Proszę wybrać prawidłową lokalizację. + + + Please enter a valid money amount. + Proszę wybrać prawidłową ilość pieniędzy. + + + Please enter a number. + Proszę wprowadzić liczbę. + + + The password is invalid. + Hasło jest nieprawidłowe. + + + Please enter a percentage value. + Proszę wprowadzić wartość procentową. + + + The values do not match. + Wartości się nie zgadzają. + + + Please enter a valid time. + Proszę wprowadzić prawidłowy czas. + + + Please select a valid timezone. + Proszę wybrać prawidłową strefę czasową. + + + Please enter a valid URL. + Proszę wprowadzić prawidłowy adres URL. + + + Please enter a valid search term. + Proszę wprowadzić prawidłowy termin wyszukiwania. + + + Please provide a valid phone number. + Proszę wprowadzić prawidłowy numer telefonu. + + + The checkbox has an invalid value. + Pole wyboru posiada nieprawidłową wartość. + + + Please enter a valid email address. + Proszę wprowadzić prawidłowy adres email. + + + Please select a valid option. + Proszę wybrać prawidłową opcję. + + + Please select a valid range. + Proszę wybrać prawidłowy zakres. + + + Please enter a valid week. + Proszę wybrać prawidłowy tydzień. + - \ No newline at end of file + From 37a2ff4563a6e10d9143435a3783eb7224be4de9 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 25 Oct 2020 12:18:37 +0100 Subject: [PATCH 085/146] [Form] Added missing German translations. --- .../Resources/translations/validators.de.xlf | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.de.xlf b/src/Symfony/Component/Form/Resources/translations/validators.de.xlf index fe4353120d256..bc8e46d1ec089 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.de.xlf @@ -18,6 +18,122 @@ This value is not a valid HTML5 color. Dieser Wert ist keine gültige HTML5 Farbe. + + Please enter a valid birthdate. + Bitte geben Sie ein gültiges Geburtsdatum ein. + + + The selected choice is invalid. + Die Auswahl ist ungültig. + + + The collection is invalid. + Diese Gruppe von Feldern ist ungültig. + + + Please select a valid color. + Bitte geben Sie eine gültige Farbe ein. + + + Please select a valid country. + Bitte wählen Sie ein gültiges Land aus. + + + Please select a valid currency. + Bitte wählen Sie eine gültige Währung aus. + + + Please choose a valid date interval. + Bitte wählen Sie ein gültiges Datumsintervall. + + + Please enter a valid date and time. + Bitte geben Sie ein gültiges Datum samt Uhrzeit ein. + + + Please enter a valid date. + Bitte geben Sie ein gültiges Datum ein. + + + Please select a valid file. + Bitte wählen Sie eine gültige Datei. + + + The hidden field is invalid. + Das versteckte Feld ist ungültig. + + + Please enter an integer. + Bitte geben Sie eine ganze Zahl ein. + + + Please select a valid language. + Bitte wählen Sie eine gültige Sprache. + + + Please select a valid locale. + Bitte wählen Sie eine gültige Locale-Einstellung aus. + + + Please enter a valid money amount. + Bitte geben Sie einen gültigen Geldbetrag ein. + + + Please enter a number. + Bitte geben Sie eine gültige Zahl ein. + + + The password is invalid. + Das Kennwort ist ungültig. + + + Please enter a percentage value. + Bitte geben Sie einen gültigen Prozentwert ein. + + + The values do not match. + Die Werte stimmen nicht überein. + + + Please enter a valid time. + Bitte geben Sie eine gültige Uhrzeit ein. + + + Please select a valid timezone. + Bitte wählen Sie eine gültige Zeitzone. + + + Please enter a valid URL. + Bitte geben Sie eine gültige URL ein. + + + Please enter a valid search term. + Bitte geben Sie einen gültigen Suchbegriff ein. + + + Please provide a valid phone number. + Bitte geben Sie eine gültige Telefonnummer ein. + + + The checkbox has an invalid value. + Das Kontrollkästchen hat einen ungültigen Wert. + + + Please enter a valid email address. + Bitte geben Sie eine gültige E-Mail-Adresse ein. + + + Please select a valid option. + Bitte wählen Sie eine gültige Option. + + + Please select a valid range. + Bitte wählen Sie einen gültigen Bereich. + + + Please enter a valid week. + Bitte geben Sie eine gültige Woche ein. + From 3d7863f5b5bb9e1835094eaeda0a8ad0ea9f646e Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 25 Oct 2020 12:33:47 +0100 Subject: [PATCH 086/146] [Security] Synchronized translations with 5.x. --- .../Security/Core/Resources/translations/security.en.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf index 3640698ce9fb3..dcc2f85efb6d6 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf @@ -66,6 +66,14 @@ Account is locked. Account is locked. + + Too many failed login attempts, please try again later. + Too many failed login attempts, please try again later. + + + Invalid or expired login link. + Invalid or expired login link. + From 54140d45fb869953c4ffee0e4b6c6dd09891d0e6 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 25 Oct 2020 13:07:34 +0100 Subject: [PATCH 087/146] [Security] Added missing German translations. --- .../Security/Core/Resources/translations/security.de.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.de.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.de.xlf index e5946ed4aa42d..c1adba7fd1f12 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.de.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.de.xlf @@ -66,6 +66,14 @@ Account is locked. Der Account ist gesperrt. + + Too many failed login attempts, please try again later. + Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es später noch einmal. + + + Invalid or expired login link. + Ungültiger oder abgelaufener Anmelde-Link. + From 00023a6ab82d7e99a1a5512af0dab0422a1e5473 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 25 Oct 2020 12:18:37 +0100 Subject: [PATCH 088/146] [Form] Added missing German translations. --- .../Resources/translations/validators.de.xlf | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.de.xlf b/src/Symfony/Component/Form/Resources/translations/validators.de.xlf index fe4353120d256..bc8e46d1ec089 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.de.xlf @@ -18,6 +18,122 @@ This value is not a valid HTML5 color. Dieser Wert ist keine gültige HTML5 Farbe. + + Please enter a valid birthdate. + Bitte geben Sie ein gültiges Geburtsdatum ein. + + + The selected choice is invalid. + Die Auswahl ist ungültig. + + + The collection is invalid. + Diese Gruppe von Feldern ist ungültig. + + + Please select a valid color. + Bitte geben Sie eine gültige Farbe ein. + + + Please select a valid country. + Bitte wählen Sie ein gültiges Land aus. + + + Please select a valid currency. + Bitte wählen Sie eine gültige Währung aus. + + + Please choose a valid date interval. + Bitte wählen Sie ein gültiges Datumsintervall. + + + Please enter a valid date and time. + Bitte geben Sie ein gültiges Datum samt Uhrzeit ein. + + + Please enter a valid date. + Bitte geben Sie ein gültiges Datum ein. + + + Please select a valid file. + Bitte wählen Sie eine gültige Datei. + + + The hidden field is invalid. + Das versteckte Feld ist ungültig. + + + Please enter an integer. + Bitte geben Sie eine ganze Zahl ein. + + + Please select a valid language. + Bitte wählen Sie eine gültige Sprache. + + + Please select a valid locale. + Bitte wählen Sie eine gültige Locale-Einstellung aus. + + + Please enter a valid money amount. + Bitte geben Sie einen gültigen Geldbetrag ein. + + + Please enter a number. + Bitte geben Sie eine gültige Zahl ein. + + + The password is invalid. + Das Kennwort ist ungültig. + + + Please enter a percentage value. + Bitte geben Sie einen gültigen Prozentwert ein. + + + The values do not match. + Die Werte stimmen nicht überein. + + + Please enter a valid time. + Bitte geben Sie eine gültige Uhrzeit ein. + + + Please select a valid timezone. + Bitte wählen Sie eine gültige Zeitzone. + + + Please enter a valid URL. + Bitte geben Sie eine gültige URL ein. + + + Please enter a valid search term. + Bitte geben Sie einen gültigen Suchbegriff ein. + + + Please provide a valid phone number. + Bitte geben Sie eine gültige Telefonnummer ein. + + + The checkbox has an invalid value. + Das Kontrollkästchen hat einen ungültigen Wert. + + + Please enter a valid email address. + Bitte geben Sie eine gültige E-Mail-Adresse ein. + + + Please select a valid option. + Bitte wählen Sie eine gültige Option. + + + Please select a valid range. + Bitte wählen Sie einen gültigen Bereich. + + + Please enter a valid week. + Bitte geben Sie eine gültige Woche ein. + From 85adad52c438a3ec221be91229a277cd5f667970 Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Sun, 25 Oct 2020 13:59:08 +0100 Subject: [PATCH 089/146] Update Security Frensh Translations --- .../Security/Core/Resources/translations/security.fr.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf index 5a77c6e9ff795..49f4a0f07482b 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf @@ -66,6 +66,14 @@ Account is locked. Le compte est bloqué. + + Too many failed login attempts, please try again later. + Plusieurs tentatives de connexion ont échoué, veuillez réessayer plus tard. + + + Invalid or expired login link. + Lien de connexion invalide ou expiré. + From 7d25a46b3bea52832f2a40fd0cf4ea5fc3796a4d Mon Sep 17 00:00:00 2001 From: Aerendir Date: Sun, 25 Oct 2020 16:26:49 +0100 Subject: [PATCH 090/146] Closes #38747: Add italian translations. --- .../Resources/translations/validators.it.xlf | 124 +++++++++++++++++- .../Resources/translations/security.it.xlf | 8 ++ 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.it.xlf b/src/Symfony/Component/Form/Resources/translations/validators.it.xlf index aa15264d9faad..8e4665ce1daf5 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.it.xlf @@ -8,11 +8,131 @@ The uploaded file was too large. Please try to upload a smaller file. - Il file caricato è troppo grande. Per favore caricare un file più piccolo. + Il file caricato è troppo grande. Per favore, carica un file più piccolo. The CSRF token is invalid. Please try to resubmit the form. - Il token CSRF non è valido. Provare a reinviare il form. + Il token CSRF non è valido. Prova a reinviare il form. + + + This value is not a valid HTML5 color. + Il valore non è un colore HTML5 valido. + + + Please enter a valid birthdate. + Per favore, inserisci una data di compleanno valida. + + + The selected choice is invalid. + La scelta selezionata non è valida. + + + The collection is invalid. + La collezione non è valida. + + + Please select a valid color. + Per favore, seleziona un colore valido. + + + Please select a valid country. + Per favore, seleziona un paese valido. + + + Please select a valid currency. + Per favore, seleziona una valuta valida. + + + Please choose a valid date interval. + Per favore, scegli a valid date interval. + + + Please enter a valid date and time. + Per favore, inserisci a valid date and time. + + + Please enter a valid date. + Per favore, inserisci a valid date. + + + Please select a valid file. + Per favore, seleziona un file valido. + + + The hidden field is invalid. + Il campo nascosto non è valido. + + + Please enter an integer. + Per favore, inserisci un numero intero. + + + Please select a valid language. + Per favore, seleziona una lingua valida. + + + Please select a valid locale. + Per favore, seleziona una lingua valida. + + + Please enter a valid money amount. + Per favore, inserisci un importo valido. + + + Please enter a number. + Per favore, inserisci un numero. + + + The password is invalid. + La password non è valida. + + + Please enter a percentage value. + Per favore, inserisci un valore percentuale. + + + The values do not match. + I valori non corrispondono. + + + Please enter a valid time. + Per favore, inserisci un orario valido. + + + Please select a valid timezone. + Per favore, seleziona un fuso orario valido. + + + Please enter a valid URL. + Per favore, inserisci un URL valido. + + + Please enter a valid search term. + Per favore, inserisci un termine di ricerca valido. + + + Please provide a valid phone number. + Per favore, indica un numero di telefono valido. + + + The checkbox has an invalid value. + La casella di selezione non ha un valore valido. + + + Please enter a valid email address. + Per favore, indica un indirizzo email valido. + + + Please select a valid option. + Per favore, seleziona un'opzione valida. + + + Please select a valid range. + Per favore, seleziona un intervallo valido. + + + Please enter a valid week. + Per favore, inserisci una settimana valida. diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.it.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.it.xlf index 75d81cc8d9312..d4a90b09351e6 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.it.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.it.xlf @@ -66,6 +66,14 @@ Account is locked. L'account è bloccato. + + Too many failed login attempts, please try again later. + Troppi tentaivi di login falliti. Riprova tra un po'. + + + Invalid or expired login link. + Link di login scaduto o non valido. + From a9d6549ce96cefcc71a842c48f53964f745f73bc Mon Sep 17 00:00:00 2001 From: Krasimir Bosilkov Date: Sun, 25 Oct 2020 18:37:37 +0200 Subject: [PATCH 091/146] [Validator] Missing Bulgarian translations #38730 --- .../Resources/translations/validators.bg.xlf | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index 1db88086cf528..8a4b0d606af66 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -334,6 +334,58 @@ This value should be valid JSON. Стойността трябва да е валиден JSON. + + This collection should contain only unique elements. + Колекцията трябва да съдържа само уникални елементи. + + + This value should be positive. + Стойността трябва да бъде положително число. + + + This value should be either positive or zero. + Стойността трябва бъде положително число или нула. + + + This value should be negative. + Стойността трябва да бъде отрицателно число. + + + This value should be either negative or zero. + Стойността трябва да бъде отрицателно число или нула. + + + This value is not a valid timezone. + Стойността не е валидна часова зона. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Тази парола е компрометирана, не трябва да бъде използвана. Моля използвайте друга парола. + + + This value should be between {{ min }} and {{ max }}. + Стойността трябва да бъде между {{ min }} и {{ max }}. + + + This value is not a valid hostname. + Стойността не е валиден hostname. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Броят на елементите в тази колекция трябва да бъде кратен на {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Стойността трябва да отговаря на поне едно от следните ограничения: + + + Each element of this collection should satisfy its own set of constraints. + Всеки елемент от тази колекция трябва да отговаря на собствения си набор от ограничения. + + + This value is not a valid International Securities Identification Number (ISIN). + Стойността не е валиден Международен идентификационен номер на ценни книжа (ISIN). + From fd7060d21ab58581cb8653e1c0fc38568f8d9a5b Mon Sep 17 00:00:00 2001 From: Krasimir Bosilkov Date: Sun, 25 Oct 2020 18:45:33 +0200 Subject: [PATCH 092/146] [Security] Missing Bulgarian translations #38730 --- .../Security/Core/Resources/translations/security.bg.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.bg.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.bg.xlf index 06692ea66a843..bb8447c778e6e 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.bg.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.bg.xlf @@ -66,6 +66,14 @@ Account is locked. Акаунта е заключен. + + Too many failed login attempts, please try again later. + Твърде много грешни опити за вход, моля опитайте по-късно. + + + Invalid or expired login link. + Невалиден или изтекъл линк за вход. + From 01cb45462c9ff505d0b1079fd0e38ef9aad94a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Holeczy?= Date: Sun, 25 Oct 2020 17:46:46 +0100 Subject: [PATCH 093/146] [Security] Add missing czech translations --- .../Security/Core/Resources/translations/security.cs.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.cs.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.cs.xlf index bd146c68049cb..fb66401c50937 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.cs.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.cs.xlf @@ -66,6 +66,14 @@ Account is locked. Účet je zablokovaný. + + Too many failed login attempts, please try again later. + Příliš mnoho nepovedených pokusů přihlášení. Zkuste to prosím později. + + + Invalid or expired login link. + Neplatný nebo expirovaný odkaz na přihlášení. + From 05be7b2f1cd85e0765e6212c81888197a35ec7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Holeczy?= Date: Sun, 25 Oct 2020 17:47:52 +0100 Subject: [PATCH 094/146] [Form] Add missing czech translations --- .../Resources/translations/validators.cs.xlf | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf index 44d597db980ec..3c4052b1ca496 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf @@ -18,6 +18,122 @@ This value is not a valid HTML5 color. Tato hodnota není platná HTML5 barva. + + Please enter a valid birthdate. + Prosím zadejte platný datum narození. + + + The selected choice is invalid. + Vybraná možnost není platná. + + + The collection is invalid. + Kolekce není platná. + + + Please select a valid color. + Prosím vyberte platnou barvu. + + + Please select a valid country. + Prosím vyberte platnou zemi. + + + Please select a valid currency. + Prosím vyberte platnou měnu. + + + Please choose a valid date interval. + Prosím vyberte platné rozpětí dat. + + + Please enter a valid date and time. + Prosím zadejte platný datum a čas. + + + Please enter a valid date. + Prosím zadejte platný datum. + + + Please select a valid file. + Prosím vyberte platný soubor. + + + The hidden field is invalid. + Skryté pole není platné. + + + Please enter an integer. + Prosím zadejte číslo. + + + Please select a valid language. + Prosím zadejte platný jazyk. + + + Please select a valid locale. + Prosím zadejte platný jazyk. + + + Please enter a valid money amount. + Prosím zadejte platnou částku. + + + Please enter a number. + Prosím zadejte číslo. + + + The password is invalid. + Heslo není platné. + + + Please enter a percentage value. + Prosím zadejte procentuální hodnotu. + + + The values do not match. + Hodnoty se neshodují. + + + Please enter a valid time. + Prosím zadejte platný čas. + + + Please select a valid timezone. + Prosím vyberte platné časové pásmo. + + + Please enter a valid URL. + Prosím zadejte platnou URL. + + + Please enter a valid search term. + Prosím zadejte platný výraz k vyhledání. + + + Please provide a valid phone number. + Prosím zadejte platné telefonní číslo. + + + The checkbox has an invalid value. + Zaškrtávací políčko má neplatnou hodnotu. + + + Please enter a valid email address. + Prosím zadejte platnou emailovou adresu. + + + Please select a valid option. + Prosím vyberte platnou možnost. + + + Please select a valid range. + Prosím vyberte platný rozsah. + + + Please enter a valid week. + Prosím zadejte platný týden. + From eaff84418f185700d03da568faf80421269c53d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Holeczy?= Date: Sun, 25 Oct 2020 17:48:25 +0100 Subject: [PATCH 095/146] [Validator] Add missing czech translations --- .../Validator/Resources/translations/validators.cs.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index ce32f1368de64..0cf53015addb6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -382,6 +382,10 @@ Each element of this collection should satisfy its own set of constraints. Každý prvek v této kolekci musí splňovat svá vlastní omezení. + + This value is not a valid International Securities Identification Number (ISIN). + Tato hodnota není platné mezinárodní identifikační číslo cenného papíru (ISIN). + From 8b307e644affbdfd3eaf02e41d8006fe31136b95 Mon Sep 17 00:00:00 2001 From: Tavo Nieves J Date: Sun, 25 Oct 2020 12:09:02 -0500 Subject: [PATCH 096/146] [Security] Added missing Spanish translations. --- .../Security/Core/Resources/translations/security.es.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.es.xlf index 00cefbb2dad67..43cb00b28a7dc 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.es.xlf @@ -66,6 +66,14 @@ Account is locked. La cuenta está bloqueada. + + Too many failed login attempts, please try again later. + Demasiados intentos fallidos de inicio de sesión, inténtelo de nuevo más tarde. + + + Invalid or expired login link. + Enlace de inicio de sesión inválido o expirado. + From 26f3963bb2a9571352a36859afe2de0dbd323579 Mon Sep 17 00:00:00 2001 From: Tavo Nieves J Date: Sun, 25 Oct 2020 12:27:57 -0500 Subject: [PATCH 097/146] [Validator] Added missing Spanish translations. --- .../Validator/Resources/translations/validators.es.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 57b07b2b5546a..2c586ca4a2571 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -382,6 +382,10 @@ Each element of this collection should satisfy its own set of constraints. Cada elemento de esta colección debería satisfacer su propio conjunto de restricciones. + + This value is not a valid International Securities Identification Number (ISIN). + Este valor no es un número de identificación internacional de valores (ISIN) válido. + From 65db8d08c8aa40ddd7468920a239c04adcceb35a Mon Sep 17 00:00:00 2001 From: tarlepp Date: Sun, 25 Oct 2020 18:43:27 +0200 Subject: [PATCH 098/146] Added missing `security.fi.xlf` translation file --- .../Resources/translations/security.fi.xlf | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/Symfony/Component/Security/Core/Resources/translations/security.fi.xlf diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.fi.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.fi.xlf new file mode 100644 index 0000000000000..d5358a6c1700c --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.fi.xlf @@ -0,0 +1,79 @@ + + + + + + An authentication exception occurred. + Autentikointi poikkeus tapahtui. + + + Authentication credentials could not be found. + Autentikoinnin tunnistetietoja ei löydetty. + + + Authentication request could not be processed due to a system problem. + Autentikointipyyntöä ei voitu käsitellä järjestelmäongelman vuoksi. + + + Invalid credentials. + Virheelliset tunnistetiedot. + + + Cookie has already been used by someone else. + Eväste on jo jonkin muun käytössä. + + + Not privileged to request the resource. + Ei oikeutta resurssiin. + + + Invalid CSRF token. + Virheellinen CSRF tunnus. + + + Digest nonce has expired. + Digest nonce on vanhentunut. + + + No authentication provider found to support the authentication token. + Autentikointi tunnukselle ei löydetty tuettua autentikointi tarjoajaa. + + + No session available, it either timed out or cookies are not enabled. + Sessio ei ole saatavilla, se on joko vanhentunut tai evästeet eivät ole käytössä. + + + No token could be found. + Tunnusta ei löytynyt. + + + Username could not be found. + Käyttäjätunnusta ei löydetty. + + + Account has expired. + Tili on vanhentunut. + + + Credentials have expired. + Tunnistetiedot ovat vanhentuneet. + + + Account is disabled. + Tili on poistettu käytöstä. + + + Account is locked. + Tili on lukittu. + + + Too many failed login attempts, please try again later. + Liian monta epäonnistunutta kirjautumisyritystä, yritä myöhemmin uudelleen. + + + Invalid or expired login link. + Virheellinen tai vanhentunut kirjautumislinkki. + + + + From e6219e4796336b2865d43aa87cc865cc08aa761f Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Sun, 25 Oct 2020 14:08:13 +0100 Subject: [PATCH 099/146] Update Security Arabic Translations --- .../Security/Core/Resources/translations/security.ar.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ar.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ar.xlf index fd18ee6ad9faf..a4e01a8f7b6b9 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.ar.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ar.xlf @@ -66,6 +66,14 @@ Account is locked. الحساب مغلق. + + Too many failed login attempts, please try again later. + عدد كبير جدا من محاولات الدخول الفاشلة، يرجى المحاولة مرة أخرى في وقت لاحق. + + + Invalid or expired login link. + رابط تسجيل الدخول غير صالح أو منتهي الصلاحية. + From b36068ff8ab2e3dd1a89efed510922c8603e88b6 Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Sun, 25 Oct 2020 14:44:30 +0100 Subject: [PATCH 100/146] Update Arabic Form Translations --- .../Resources/translations/validators.ar.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf index 990b039d63d4c..e30daaf1dff5d 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. قيمة رمز الموقع غير صحيحة. من فضلك اعد ارسال النموذج. + + This value is not a valid HTML5 color. + هذه القيمة ليست لون HTML5 صالحًا. + + + Please enter a valid birthdate. + الرجاء ادخال تاريخ ميلاد صالح. + + + The selected choice is invalid. + الاختيار المحدد غير صالح. + + + The collection is invalid. + المجموعة غير صالحة. + + + Please select a valid color. + الرجاء اختيار لون صالح. + + + Please select a valid country. + الرجاء اختيار بلد صالح. + + + Please select a valid currency. + الرجاء اختيار عملة صالحة. + + + Please choose a valid date interval. + الرجاء اختيار فاصل زمني صالح. + + + Please enter a valid date and time. + الرجاء إدخال تاريخ ووقت صالحين. + + + Please enter a valid date. + الرجاء إدخال تاريخ صالح. + + + Please select a valid file. + الرجاء اختيار ملف صالح. + + + The hidden field is invalid. + الحقل المخفي غير صالح. + + + Please enter an integer. + الرجاء إدخال عدد صحيح. + + + Please select a valid language. + الرجاء اختيار لغة صالحة. + + + Please select a valid locale. + الرجاء اختيار لغة صالحة. + + + Please enter a valid money amount. + الرجاء إدخال مبلغ مالي صالح. + + + Please enter a number. + الرجاء إدخال رقم. + + + The password is invalid. + كلمة المرور غير صحيحة. + + + Please enter a percentage value. + الرجاء إدخال قيمة النسبة المئوية. + + + The values do not match. + القيم لا تتطابق. + + + Please enter a valid time. + الرجاء إدخال وقت صالح. + + + Please select a valid timezone. + الرجاء تحديد منطقة زمنية صالحة. + + + Please enter a valid URL. + أدخل عنوان الرابط صحيح من فضلك. + + + Please enter a valid search term. + الرجاء إدخال مصطلح البحث ساري المفعول. + + + Please provide a valid phone number. + يرجى تقديم رقم هاتف صالح. + + + The checkbox has an invalid value. + خانة الاختيار لها قيمة غير صالحة. + + + Please enter a valid email address. + رجاء قم بإدخال بريد الكتروني صحيح + + + Please select a valid option. + الرجاء تحديد خيار صالح. + + + Please select a valid range. + يرجى تحديد نطاق صالح. + + + Please enter a valid week. + الرجاء إدخال أسبوع صالح. + From 8c5d26fcb2bd52d6c92c1206dd980bb8c75f0d56 Mon Sep 17 00:00:00 2001 From: Krasimir Bosilkov Date: Sun, 25 Oct 2020 18:42:28 +0200 Subject: [PATCH 101/146] [Form] Missing Bulgarian translations --- .../Resources/translations/validators.bg.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf index 5c768c305f9ee..32fa9433108c1 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. Невалиден CSRF токен. Моля, опитайте да изпратите формата отново. + + This value is not a valid HTML5 color. + Стойността не е валиден HTML5 цвят. + + + Please enter a valid birthdate. + Моля въведете валидна дата на раждане. + + + The selected choice is invalid. + Избраните стойности не са валидни. + + + The collection is invalid. + Колекцията не е валидна. + + + Please select a valid color. + Моля изберете валиден цвят. + + + Please select a valid country. + Моля изберете валидна държава. + + + Please select a valid currency. + Моля изберете валидна валута. + + + Please choose a valid date interval. + Моля изберете валиден интервал от дати. + + + Please enter a valid date and time. + Моля въведете валидни дата и час. + + + Please enter a valid date. + Моля въведете валидна дата. + + + Please select a valid file. + Моля изберете валиден файл. + + + The hidden field is invalid. + Скритото поле е невалидно. + + + Please enter an integer. + Моля попълнете цяло число. + + + Please select a valid language. + Моля изберете валиден език. + + + Please select a valid locale. + Моля изберете валиден език. + + + Please enter a valid money amount. + Моля въведете валидна парична сума. + + + Please enter a number. + Моля въведете число. + + + The password is invalid. + Паролата е невалидна. + + + Please enter a percentage value. + Моля въведете процентна стойност. + + + The values do not match. + Стойностите не съвпадат. + + + Please enter a valid time. + Моля въведете валидно време. + + + Please select a valid timezone. + Моля изберете валидна часова зона. + + + Please enter a valid URL. + Моля въведете валиден URL. + + + Please enter a valid search term. + Моля въведете валидно търсене. + + + Please provide a valid phone number. + Моля осигурете валиден телефонен номер. + + + The checkbox has an invalid value. + Отметката има невалидна стойност. + + + Please enter a valid email address. + Моля въведете валидна ел. поща. + + + Please select a valid option. + Моля изберете валидна опция. + + + Please select a valid range. + Моля изберете валиден обхват. + + + Please enter a valid week. + Моля въведете валидна седмица. + From ac0e25e885b348e4d57d558ee548af61a195e628 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 25 Oct 2020 18:31:25 +0100 Subject: [PATCH 102/146] [Cache] Fixed tests.. again --- src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php | 1 + src/Symfony/Component/Cache/composer.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php index 36bf3c4a39f5b..909b5f87ceabd 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Contracts\Cache\ItemInterface; /** diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index b004154cd4ca8..49f634b372959 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -36,6 +36,7 @@ "psr/simple-cache": "^1.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", "symfony/var-dumper": "^4.4|^5.0" }, "conflict": { From 6289b271aad9935f9f58d476cb02917a5097c361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Sun, 25 Oct 2020 18:23:35 +0100 Subject: [PATCH 103/146] Add missing vietnamese translations --- .../Resources/translations/validators.vi.xlf | 20 +++++++++++++++++++ .../Resources/translations/security.vi.xlf | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Form/Resources/translations/validators.vi.xlf index 4d060fbe0d96e..6a8f2bd862c9d 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.vi.xlf @@ -114,6 +114,26 @@ Please provide a valid phone number. Vui lòng cung cấp số điện thoại hợp lệ. + + The checkbox has an invalid value. + Hộp kiểm có một giá trị không hợp lệ. + + + Please enter a valid email address. + Vui lòng nhập địa chỉ email hợp lệ. + + + Please select a valid option. + Vui lòng chọn một phương án hợp lệ. + + + Please select a valid range. + Vui lòng nhập một phạm vi hợp lệ. + + + Please enter a valid week. + Vui lòng nhập một tuần hợp lệ. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.vi.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.vi.xlf index 93723bb43ecea..6cda1572e4e3b 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.vi.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.vi.xlf @@ -66,6 +66,14 @@ Account is locked. Tài khoản bị khóa. + + Too many failed login attempts, please try again later. + Đăng nhập sai quá nhiều lần, vui lòng thử lại lần nữa. + + + Invalid or expired login link. + Liên kết đăng nhập không hợp lệ hoặc quá hạn. + From 7f2b13bcb3b0e1a31c42757c426a13167be9c18b Mon Sep 17 00:00:00 2001 From: Andrew M-Y Date: Sun, 25 Oct 2020 21:00:32 +0200 Subject: [PATCH 104/146] [Security] Add missing Latvian translations --- .../Core/Resources/translations/security.lv.xlf | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.lv.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.lv.xlf index 33c48c617461c..05967eaf61c28 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.lv.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.lv.xlf @@ -66,6 +66,14 @@ Account is locked. Konts ir slēgts. + + Too many failed login attempts, please try again later. + Pārāk daudz atteiktu ieejas mēģinājumu, lūdzu, mēģiniet vēlreiz vēlāk. + + + Invalid or expired login link. + Ieejas saite ir nederīga vai arī tai ir beidzies derīguma termiņš. + - \ No newline at end of file + From b452e18ebc2a14be264472d50510bb18e760a18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 25 Oct 2020 19:00:57 +0100 Subject: [PATCH 105/146] Fix transient tests --- .../Component/Cache/Tests/Adapter/AdapterTestCase.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 05b863d1ac110..57c355eaa43a6 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -116,11 +116,11 @@ public function testGetMetadata() $item = $cache->getItem('foo'); - $expected = [ - CacheItem::METADATA_EXPIRY => 9.5 + time(), - CacheItem::METADATA_CTIME => 1000, - ]; - $this->assertEqualsWithDelta($expected, $item->getMetadata(), .6, 'Item metadata should embed expiry and ctime.'); + $metadata = $item->getMetadata(); + $this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata); + $this->assertEqualsWithDelta(1000, $metadata[CacheItem::METADATA_CTIME], 6); + $this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata); + $this->assertEqualsWithDelta(9.5 + time(), $metadata[CacheItem::METADATA_EXPIRY], 0.6); } public function testDefaultLifeTime() From 871c983164f9aff8d05a3b6ae132681fe2c0d4f0 Mon Sep 17 00:00:00 2001 From: Andrew M-Y Date: Sun, 25 Oct 2020 20:47:41 +0200 Subject: [PATCH 106/146] [Form] Add missing Latvian translations --- .../Resources/translations/validators.lv.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf index 9cdfb2cd4864f..e7c90c793ede1 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. Dotais CSRF talons nav derīgs. Lūdzu mēģiniet vēlreiz iesniegt veidlapu. + + This value is not a valid HTML5 color. + Šī vertība nav derīga HTML5 krāsa. + + + Please enter a valid birthdate. + Lūdzu, ievadiet derīgu dzimšanas datumu. + + + The selected choice is invalid. + Iezīmētā izvēle nav derīga. + + + The collection is invalid. + Kolekcija nav derīga. + + + Please select a valid color. + Lūdzu, izvēlieties derīgu krāsu. + + + Please select a valid country. + Lūdzu, izvēlieties derīgu valsti. + + + Please select a valid currency. + Lūdzu, izvēlieties derīgu valūtu. + + + Please choose a valid date interval. + Lūdzu, izvēlieties derīgu datumu intervālu. + + + Please enter a valid date and time. + Lūdzu, ievadiet derīgu datumu un laiku. + + + Please enter a valid date. + Lūdzu, ievadiet derīgu datumu. + + + Please select a valid file. + Lūdzu, izvēlieties derīgu failu. + + + The hidden field is invalid. + Slēptā lauka vērtība ir nederīga. + + + Please enter an integer. + Lūdzu, ievadiet veselu skaitli. + + + Please select a valid language. + Lūdzu, izvēlieties derīgu valodu. + + + Please select a valid locale. + Lūdzu, izvēlieties derīgu lokalizāciju. + + + Please enter a valid money amount. + Lūdzu, ievadiet derīgu naudas lielumu. + + + Please enter a number. + Lūdzu, ievadiet skaitli. + + + The password is invalid. + Parole ir nederīga. + + + Please enter a percentage value. + Lūdzu, ievadiet procentuālo lielumu. + + + The values do not match. + Vērtības nesakrīt. + + + Please enter a valid time. + Lūdzu, ievadiet derīgu laiku. + + + Please select a valid timezone. + Lūdzu, izvēlieties derīgu laika zonu. + + + Please enter a valid URL. + Lūdzu, ievadiet derīgu URL. + + + Please enter a valid search term. + Lūdzu, ievadiet derīgu meklēšanas nosacījumu. + + + Please provide a valid phone number. + Lūdzu, ievadiet derīgu tālruņa numuru. + + + The checkbox has an invalid value. + Izvēles rūtiņai ir nederīga vērtība. + + + Please enter a valid email address. + Lūdzu, ievadiet derīgu e-pasta adresi. + + + Please select a valid option. + Lūdzu, izvēlieties derīgu opciju. + + + Please select a valid range. + Lūdzu, izvēlieties derīgu diapazonu. + + + Please enter a valid week. + Lūdzu, ievadiet derīgu nedeļu. + From 4924b38d3a69d67dd6725347fcfa143bdf22cdb4 Mon Sep 17 00:00:00 2001 From: Andrew M-Y Date: Sun, 25 Oct 2020 21:13:39 +0200 Subject: [PATCH 107/146] [Validator] Add missing Latvian translations --- .../Resources/translations/validators.lv.xlf | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index 4c0e192521d27..d70ffbc722d51 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -334,6 +334,58 @@ This value should be valid JSON. Šai vērtībai jābūt derīgam JSON. + + This collection should contain only unique elements. + Šai kolekcijai jāsatur tikai derīgi elementi. + + + This value should be positive. + Šai vērtībāi jābūt pozitīvai. + + + This value should be either positive or zero. + Šai vērtībāi jābūt pozitīvai vai vienādai ar nulli. + + + This value should be negative. + Šai vērtībāi jābūt negatīvai. + + + This value should be either negative or zero. + Šai vērtībāi jābūt negatīvai vai vienādai ar nulli. + + + This value is not a valid timezone. + Šī vērtība nav derīga laika zona. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Šī parole tika publicēta datu noplūdē, viņu nedrīkst izmantot. Lūdzu, izvēlieties citu paroli. + + + This value should be between {{ min }} and {{ max }}. + Šai vērtībai jābūt starp {{ min }} un {{ max }}. + + + This value is not a valid hostname. + Šī vērtība nav derīgs tīmekļa servera nosaukums. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Elementu skaitam šajā kolekcijā jābūt {{ compared_value }} reizinājumam. + + + This value should satisfy at least one of the following constraints: + Šai vērtībai jāiekļaujas vismaz vienā no sekojošiem ierobežojumiem: + + + Each element of this collection should satisfy its own set of constraints. + Šīs kolekcijas katram elementam jāiekļaujas savā ierobežojumu kopā. + + + This value is not a valid International Securities Identification Number (ISIN). + Šī vērtība nav derīgs starptautiskais vērtspapīru identifikācijas numurs (ISIN). + From 987efdd6205ea203cfa9ef92a88e687f5228f9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 25 Oct 2020 21:41:30 +0100 Subject: [PATCH 108/146] Fix transient tests --- .../HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 22cadf7129528..fd67af368b740 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -216,7 +216,7 @@ public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndVali $cacheStrategy->add($embeddedResponse); $cacheStrategy->update($masterResponse); - $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage')); + $this->assertEqualsWithDelta(60, (int) $masterResponse->headers->getCacheControlDirective('s-maxage'), 1); } public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombinesExpirationAndValidation() From 5dd70bd62e7e6ce50743a24d5c9db9be0ddfa1db Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 25 Oct 2020 14:52:25 +0100 Subject: [PATCH 109/146] [Security] Move AbstractListener abstract methods to the new FirewallListenerInterface --- .../Debug/TraceableFirewallListener.php | 6 ++--- .../Debug/WrappedLazyListener.php | 3 ++- .../Security/LazyFirewallContext.php | 6 ++--- .../SortFirewallListenersPassTest.php | 26 +++++++++++++++++++ src/Symfony/Component/Security/CHANGELOG.md | 1 + .../AuthenticatorManagerInterface.php | 4 +-- .../Http/Firewall/AbstractListener.php | 13 ---------- .../Firewall/FirewallListenerInterface.php | 19 +++++++++++++- 8 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php index e7f9df1221e69..bc7549a97a34d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php @@ -15,7 +15,7 @@ use Symfony\Bundle\SecurityBundle\Security\FirewallContext; use Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext; use Symfony\Component\HttpKernel\Event\RequestEvent; -use Symfony\Component\Security\Http\Firewall\AbstractListener; +use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; /** * Firewall collecting called listeners. @@ -41,7 +41,7 @@ protected function callListeners(RequestEvent $event, iterable $listeners) \Closure::bind(function () use (&$wrappedLazyListeners, &$wrappedListeners) { $listeners = []; foreach ($this->listeners as $listener) { - if ($listener instanceof AbstractListener) { + if ($listener instanceof FirewallListenerInterface) { $listener = new WrappedLazyListener($listener); $listeners[] = $listener; $wrappedLazyListeners[] = $listener; @@ -58,7 +58,7 @@ protected function callListeners(RequestEvent $event, iterable $listeners) $listener($event); } else { - $wrappedListener = $listener instanceof AbstractListener ? new WrappedLazyListener($listener) : new WrappedListener($listener); + $wrappedListener = $listener instanceof FirewallListenerInterface ? new WrappedLazyListener($listener) : new WrappedListener($listener); $wrappedListener($event); $wrappedListeners[] = $wrappedListener->getInfo(); } diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php index 8e06d6ed1eeb0..5a3d0a1c609d8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Core\Exception\LazyResponseException; use Symfony\Component\Security\Http\Firewall\AbstractListener; +use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; /** * Wraps a lazy security listener. @@ -27,7 +28,7 @@ final class WrappedLazyListener extends AbstractListener { use TraceableListenerTrait; - public function __construct(AbstractListener $listener) + public function __construct(FirewallListenerInterface $listener) { $this->listener = $listener; } diff --git a/src/Symfony/Bundle/SecurityBundle/Security/LazyFirewallContext.php b/src/Symfony/Bundle/SecurityBundle/Security/LazyFirewallContext.php index 30229b392048d..9d8396a8830c9 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/LazyFirewallContext.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/LazyFirewallContext.php @@ -14,8 +14,8 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Http\Event\LazyResponseEvent; -use Symfony\Component\Security\Http\Firewall\AbstractListener; use Symfony\Component\Security\Http\Firewall\ExceptionListener; +use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; use Symfony\Component\Security\Http\Firewall\LogoutListener; /** @@ -46,9 +46,9 @@ public function __invoke(RequestEvent $event) $lazy = $request->isMethodCacheable(); foreach (parent::getListeners() as $listener) { - if (!$lazy || !$listener instanceof AbstractListener) { + if (!$lazy || !$listener instanceof FirewallListenerInterface) { $listeners[] = $listener; - $lazy = $lazy && $listener instanceof AbstractListener; + $lazy = $lazy && $listener instanceof FirewallListenerInterface; } elseif (false !== $supports = $listener->supports($request)) { $listeners[] = [$listener, 'authenticate']; $lazy = null === $supports; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/SortFirewallListenersPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/SortFirewallListenersPassTest.php index 32f11f45cb58d..8cbf745e9cc88 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/SortFirewallListenersPassTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/SortFirewallListenersPassTest.php @@ -17,6 +17,8 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; class SortFirewallListenersPassTest extends TestCase @@ -59,6 +61,14 @@ public function testSortFirewallListeners() class FirewallListenerPriorityMinus1 implements FirewallListenerInterface { + public function supports(Request $request): ?bool + { + } + + public function authenticate(RequestEvent $event) + { + } + public static function getPriority(): int { return -1; @@ -67,6 +77,14 @@ public static function getPriority(): int class FirewallListenerPriority1 implements FirewallListenerInterface { + public function supports(Request $request): ?bool + { + } + + public function authenticate(RequestEvent $event) + { + } + public static function getPriority(): int { return 1; @@ -75,6 +93,14 @@ public static function getPriority(): int class FirewallListenerPriority2 implements FirewallListenerInterface { + public function supports(Request $request): ?bool + { + } + + public function authenticate(RequestEvent $event) + { + } + public static function getPriority(): int { return 2; diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index e3ba09c8f2556..b6e7ca04dcd68 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -14,6 +14,7 @@ CHANGELOG * Added a CurrentUser attribute to force the UserValueResolver to resolve an argument to the current user. * Added `LoginThrottlingListener`. * Added `LoginLinkAuthenticator`. + * Moved methods `supports()` and `authenticate()` from `AbstractListener` to `FirewallListenerInterface`. 5.1.0 ----- diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManagerInterface.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManagerInterface.php index 391ccc74f300e..dfbd6dc14659a 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManagerInterface.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManagerInterface.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Http\Firewall\AbstractListener; +use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; /** * @author Wouter de Jong @@ -26,7 +26,7 @@ interface AuthenticatorManagerInterface /** * Called to see if authentication should be attempted on this request. * - * @see AbstractListener::supports() + * @see FirewallListenerInterface::supports() */ public function supports(Request $request): ?bool; diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractListener.php index 31fb05dd26756..cbc8f9382115f 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractListener.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\RequestEvent; /** @@ -28,18 +27,6 @@ final public function __invoke(RequestEvent $event) } } - /** - * Tells whether the authenticate() method should be called or not depending on the incoming request. - * - * Returning null means authenticate() can be called lazily when accessing the token storage. - */ - abstract public function supports(Request $request): ?bool; - - /** - * Does whatever is required to authenticate the request, typically calling $event->setResponse() internally. - */ - abstract public function authenticate(RequestEvent $event); - public static function getPriority(): int { return 0; // Default diff --git a/src/Symfony/Component/Security/Http/Firewall/FirewallListenerInterface.php b/src/Symfony/Component/Security/Http/Firewall/FirewallListenerInterface.php index 3b8eeca618bc4..485d767c715f8 100644 --- a/src/Symfony/Component/Security/Http/Firewall/FirewallListenerInterface.php +++ b/src/Symfony/Component/Security/Http/Firewall/FirewallListenerInterface.php @@ -11,13 +11,30 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\RequestEvent; + /** - * Can be implemented by firewall listeners to define their priority in execution. + * Can be implemented by firewall listeners. * * @author Christian Scheb + * @author Nicolas Grekas + * @author Robin Chalas */ interface FirewallListenerInterface { + /** + * Tells whether the authenticate() method should be called or not depending on the incoming request. + * + * Returning null means authenticate() can be called lazily when accessing the token storage. + */ + public function supports(Request $request): ?bool; + + /** + * Does whatever is required to authenticate the request, typically calling $event->setResponse() internally. + */ + public function authenticate(RequestEvent $event); + /** * Defines the priority of the listener. * The higher the number, the earlier a listener is executed. From fd05fc6afb405e85d97e62f91c75a161c6ce1f72 Mon Sep 17 00:00:00 2001 From: Adiel Cristo Date: Sun, 25 Oct 2020 16:43:12 -0300 Subject: [PATCH 110/146] [Form] [Security] Add missing pt_BR translations --- .../translations/validators.pt_BR.xlf | 20 +++++++++++++++++++ .../Resources/translations/security.pt_BR.xlf | 16 +++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf index 3e79f391ad1f3..37717fe983dd9 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf @@ -114,6 +114,26 @@ Please provide a valid phone number. Por favor, informe um telefone válido. + + The checkbox has an invalid value. + A caixa de seleção possui um valor inválido. + + + Please enter a valid email address. + Por favor, informe um endereço de e-mail válido. + + + Please select a valid option. + Por favor, selecione uma opção válida. + + + Please select a valid range. + Por favor, selecione um intervalo válido. + + + Please enter a valid week. + Por favor, informe uma semana válida. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.pt_BR.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.pt_BR.xlf index 61685d9f052ea..1c27248cd8ed0 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.pt_BR.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.pt_BR.xlf @@ -12,7 +12,7 @@ Authentication request could not be processed due to a system problem. - A autenticação não pôde ser concluída devido a um problema no sistema. + A solicitação de autenticação não pôde ser processada devido a um problema no sistema. Invalid credentials. @@ -20,11 +20,11 @@ Cookie has already been used by someone else. - Este cookie já está em uso. + Este cookie já foi usado por outra pessoa. Not privileged to request the resource. - Não possui privilégios o bastante para requisitar este recurso. + Sem privilégio para solicitar o recurso. Invalid CSRF token. @@ -40,7 +40,7 @@ No session available, it either timed out or cookies are not enabled. - Nenhuma sessão disponível, ela expirou ou os cookies estão desativados. + Nenhuma sessão disponível, ela expirou ou os cookies não estão habilitados. No token could be found. @@ -66,6 +66,14 @@ Account is locked. A conta está travada. + + Too many failed login attempts, please try again later. + Muitas tentativas de login malsucedidas, tente novamente mais tarde. + + + Invalid or expired login link. + Link de login inválido ou expirado. + From 6a9e274a1019a9f833be1d56a6004085eed19ea9 Mon Sep 17 00:00:00 2001 From: Dmitriy Mamontov Date: Sun, 25 Oct 2020 23:09:05 +0300 Subject: [PATCH 111/146] Added missing translations for Russian --- .../Resources/translations/validators.ru.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.ru.xlf | 8 ++ .../Resources/translations/validators.ru.xlf | 4 + 3 files changed, 132 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf index fbbbeb442297c..b11b7cef57a31 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF значение недопустимо. Пожалуйста, попробуйте повторить отправку формы. + + This value is not a valid HTML5 color. + Значение не является допустимым HTML5 цветом. + + + Please enter a valid birthdate. + Пожалуйста, введите действительную дату рождения. + + + The selected choice is invalid. + Выбранный вариант недопустим. + + + The collection is invalid. + Коллекция недопустима. + + + Please select a valid color. + Пожалуйста, выберите допустимый цвет. + + + Please select a valid country. + Пожалуйста, выберите действительную страну. + + + Please select a valid currency. + Пожалуйста, выберите действительную валюту. + + + Please choose a valid date interval. + Пожалуйста, выберите действительный период. + + + Please enter a valid date and time. + Пожалуйста, введите действительные дату и время. + + + Please enter a valid date. + Пожалуйста, введите действительную дату. + + + Please select a valid file. + Пожалуйста, выберите допустимый файл. + + + The hidden field is invalid. + Значение скрытого поля недопустимо. + + + Please enter an integer. + Пожалуйста, введите целое число. + + + Please select a valid language. + Пожалуйста, выберите допустимый язык. + + + Please select a valid locale. + Пожалуйста, выберите допустимую локаль. + + + Please enter a valid money amount. + Пожалуйста, введите допустимое количество денег. + + + Please enter a number. + Пожалуйста, введите номер. + + + The password is invalid. + Пароль недействителен. + + + Please enter a percentage value. + Пожалуйста, введите процентное значение. + + + The values do not match. + Значения не совпадают. + + + Please enter a valid time. + Пожалуйста, введите действительное время. + + + Please select a valid timezone. + Пожалуйста, выберите действительный часовой пояс. + + + Please enter a valid URL. + Пожалуйста, введите действительный URL. + + + Please enter a valid search term. + Пожалуйста, введите действительный поисковый запрос. + + + Please provide a valid phone number. + Пожалуйста, введите действительный номер телефона. + + + The checkbox has an invalid value. + Флажок имеет недопустимое значение. + + + Please enter a valid email address. + Пожалуйста, введите допустимый email адрес. + + + Please select a valid option. + Пожалуйста, выберите допустимый вариант. + + + Please select a valid range. + Пожалуйста, выберите допустимый диапазон. + + + Please enter a valid week. + Пожалуйста, введите действительную неделю. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ru.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ru.xlf index 1964f95e09a64..0468c8373b91a 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.ru.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ru.xlf @@ -66,6 +66,14 @@ Account is locked. Учетная запись заблокирована. + + Too many failed login attempts, please try again later. + Слишком много неудачных попыток входа, пожалуйста, попробуйте позже. + + + Invalid or expired login link. + Ссылка для входа недействительна или просрочена. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 3c03fd8525cca..516fa2cf2a8bb 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -382,6 +382,10 @@ Each element of this collection should satisfy its own set of constraints. Каждый элемент этой коллекции должен удовлетворять своему собственному набору ограничений. + + This value is not a valid International Securities Identification Number (ISIN). + Значение не является корректным международным идентификационным номером ценных бумаг (ISIN). + From 9376e8778dc0d65d5ff5cb1d7234a019d61c1530 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 25 Oct 2020 23:11:08 +0100 Subject: [PATCH 112/146] [Security] Remove dead references to AnonymousAuthenticator --- .../Security/Http/Authentication/AuthenticatorManager.php | 3 +-- .../Http/Tests/Authentication/AuthenticatorManagerTest.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php index a9bdf8a36f236..17d2407db6fee 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php @@ -129,8 +129,7 @@ private function executeAuthenticators(array $authenticators, Request $request): foreach ($authenticators as $authenticator) { // recheck if the authenticator still supports the listener. supports() is called // eagerly (before token storage is initialized), whereas authenticate() is called - // lazily (after initialization). This is important for e.g. the AnonymousAuthenticator - // as its support is relying on the (initialized) token in the TokenStorage. + // lazily (after initialization). if (false === $authenticator->supports($request)) { if (null !== $this->logger) { $this->logger->debug('Skipping the "{authenticator}" authenticator as it did not support the request.', ['authenticator' => \get_class($authenticator)]); diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php index 3469c4813eb14..8c14f31d81ecd 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/AuthenticatorManagerTest.php @@ -71,7 +71,7 @@ public function testSupportCheckedUponRequestAuthentication() { // the attribute stores the supported authenticators, returning false now // means support changed between calling supports() and authenticateRequest() - // (which is the case with lazy firewalls and e.g. the AnonymousAuthenticator) + // (which is the case with lazy firewalls) $authenticator = $this->createAuthenticator(false); $this->request->attributes->set('_security_authenticators', [$authenticator]); From 1044b1e85228c25df30377ab1e31e6b454f755ac Mon Sep 17 00:00:00 2001 From: Eric Krona Date: Sun, 25 Oct 2020 22:52:15 +0100 Subject: [PATCH 113/146] Fix #38765 Added missing swedish translations for Form, Security and Validator components Update src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf Co-authored-by: Tobias Nyholm Update src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf Co-authored-by: Tobias Nyholm --- .../Resources/translations/validators.sv.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.sv.xlf | 8 ++ .../Resources/translations/validators.sv.xlf | 21 +++ 3 files changed, 149 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf index 2a5e57ca81b36..dff88e98f1041 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF-elementet är inte giltigt. Försök att skicka formuläret igen. + + This value is not a valid HTML5 color. + Värdet är inte en giltig HTML5-färg. + + + Please enter a valid birthdate. + Ange ett giltigt födelsedatum. + + + The selected choice is invalid. + Det valda alternativet är ogiltigt. + + + The collection is invalid. + Den här samlingen är ogiltig. + + + Please select a valid color. + Välj en giltig färg. + + + Please select a valid country. + Välj ett land. + + + Please select a valid currency. + Välj en valuta. + + + Please choose a valid date interval. + Välj ett giltigt datumintervall. + + + Please enter a valid date and time. + Ange datum och tid. + + + Please enter a valid date. + Ange ett datum. + + + Please select a valid file. + Välj en fil. + + + The hidden field is invalid. + Det dolda fältet är ogiltigt. + + + Please enter an integer. + Ange ett heltal. + + + Please select a valid language. + Välj språk. + + + Please select a valid locale. + Välj plats. + + + Please enter a valid money amount. + Ange en giltig summa pengar. + + + Please enter a number. + Ange en siffra. + + + The password is invalid. + Lösenordet är ogiltigt. + + + Please enter a percentage value. + Ange ett procentuellt värde. + + + The values do not match. + De angivna värdena stämmer inte överens. + + + Please enter a valid time. + Ange en giltig tid. + + + Please select a valid timezone. + Välj tidszon. + + + Please enter a valid URL. + Ange en giltig URL. + + + Please enter a valid search term. + Ange ett giltigt sökbegrepp. + + + Please provide a valid phone number. + Ange ett giltigt telefonnummer. + + + The checkbox has an invalid value. + Kryssrutan har ett ogiltigt värde. + + + Please enter a valid email address. + Ange en giltig e-postadress. + + + Please select a valid option. + Välj ett alternativ. + + + Please select a valid range. + Välj ett intervall. + + + Please enter a valid week. + Ange en vecka. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.sv.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.sv.xlf index b5f62092365fa..6e660f79a30dd 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.sv.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.sv.xlf @@ -66,6 +66,14 @@ Account is locked. Kontot är låst. + + Too many failed login attempts, please try again later. + För många misslyckade inloggningsförsök, försök igen senare. + + + Invalid or expired login link. + Ogiltig eller utgången inloggningslänk. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index bf7da2f06c907..4f2ae8c78ea12 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -366,6 +366,27 @@ This value should be between {{ min }} and {{ max }}. Detta värde bör ligga mellan {{ min }} och {{ max }}. + + This value is not a valid hostname. + Värdet är inte ett giltigt servernamn. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Antalet element i samlingen ska vara en multipel av {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Det här värdet skall uppfylla minst ett av följande krav: + + + Each element of this collection should satisfy its own set of constraints. + Varje element i samlingen skall uppfylla sin egen uppsättning av krav. + + + This value is not a valid International Securities Identification Number (ISIN). + Det här värdet är inte ett giltigt "International Securities Identification Number" (ISIN). + + From dd2d320e378d4623919ece34b7f0fc5bbce13abd Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Sun, 25 Oct 2020 14:26:21 +0100 Subject: [PATCH 114/146] Update French Translations for Validator Component --- .../Resources/translations/validators.fr.xlf | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf index a32c83fc93026..f40dea752d3dd 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf @@ -18,6 +18,122 @@ This value is not a valid HTML5 color. Cette valeur n'est pas une couleur HTML5 valide. + + Please enter a valid birthdate. + Veuillez entrer une date de naissance valide. + + + The selected choice is invalid. + Le choix sélectionné est invalide. + + + The collection is invalid. + La collection est invalide. + + + Please select a valid color. + Veuillez sélectionner une couleur valide. + + + Please select a valid country. + Veuillez sélectionner un pays valide. + + + Please select a valid currency. + Veuillez sélectionner une devise valide. + + + Please choose a valid date interval. + Veuillez choisir un intervalle de dates valide. + + + Please enter a valid date and time. + Veuillez saisir une date et une heure valides. + + + Please enter a valid date. + Veuillez entrer une date valide. + + + Please select a valid file. + Veuillez sélectionner un fichier valide. + + + The hidden field is invalid. + Le champ masqué n'est pas valide. + + + Please enter an integer. + Veuillez saisir un entier. + + + Please select a valid language. + Veuillez sélectionner une langue valide. + + + Please select a valid locale. + Veuillez sélectionner une langue valide. + + + Please enter a valid money amount. + Veuillez saisir un montant valide. + + + Please enter a number. + Veuillez saisir un nombre. + + + The password is invalid. + Le mot de passe est invalide. + + + Please enter a percentage value. + Veuillez saisir un pourcentage valide. + + + The values do not match. + Les valeurs ne correspondent pas. + + + Please enter a valid time. + Veuillez saisir une heure valide. + + + Please select a valid timezone. + Veuillez sélectionner un fuseau horaire valide. + + + Please enter a valid URL. + Veuillez saisir une URL valide. + + + Please enter a valid search term. + Veuillez saisir un terme de recherche valide. + + + Please provide a valid phone number. + Veuillez fournir un numéro de téléphone valide. + + + The checkbox has an invalid value. + La case à cocher a une valeur non valide. + + + Please enter a valid email address. + Veuillez saisir une adresse email valide. + + + Please select a valid option. + Veuillez sélectionner une option valide. + + + Please select a valid range. + Veuillez sélectionner une plage valide. + + + Please enter a valid week. + Veuillez entrer une semaine valide. + From a78b01140e23360cf47804b5df731f21dec8b933 Mon Sep 17 00:00:00 2001 From: Indra Gunawan Date: Mon, 26 Oct 2020 11:50:45 +0700 Subject: [PATCH 115/146] sync id translation --- .../Resources/translations/validators.id.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.id.xlf | 8 ++ .../Resources/translations/validators.id.xlf | 56 ++++++++ 3 files changed, 184 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.id.xlf b/src/Symfony/Component/Form/Resources/translations/validators.id.xlf index b067d98474fac..535f9e6b15860 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.id.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF-Token tidak sah. Silahkan coba kirim ulang formulir. + + This value is not a valid HTML5 color. + Nilai ini bukan merupakan HTML5 color yang sah. + + + Please enter a valid birthdate. + Silahkan masukkan tanggal lahir yang sah. + + + The selected choice is invalid. + Pilihan yang dipilih tidak sah. + + + The collection is invalid. + Koleksi tidak sah. + + + Please select a valid color. + Silahkan pilih warna yang sah. + + + Please select a valid country. + Silahkan pilih negara yang sah. + + + Please select a valid currency. + Silahkan pilih mata uang yang sah. + + + Please choose a valid date interval. + Silahkan pilih interval tanggal yang sah. + + + Please enter a valid date and time. + Silahkan masukkan tanggal dan waktu yang sah. + + + Please enter a valid date. + Silahkan masukkan tanggal yang sah. + + + Please select a valid file. + Silahkan pilih berkas yang sah. + + + The hidden field is invalid. + Ruas yang tersembunyi tidak sah. + + + Please enter an integer. + Silahkan masukkan angka. + + + Please select a valid language. + Silahlan pilih bahasa yang sah. + + + Please select a valid locale. + Silahkan pilih local yang sah. + + + Please enter a valid money amount. + Silahkan masukkan nilai uang yang sah. + + + Please enter a number. + Silahkan masukkan sebuah angka + + + The password is invalid. + Kata sandi tidak sah. + + + Please enter a percentage value. + Silahkan masukkan sebuah nilai persentase. + + + The values do not match. + Nilainya tidak cocok. + + + Please enter a valid time. + Silahkan masukkan waktu yang sah. + + + Please select a valid timezone. + Silahkan pilih zona waktu yang sah. + + + Please enter a valid URL. + Silahkan masukkan URL yang sah. + + + Please enter a valid search term. + Silahkan masukkan kata pencarian yang sah. + + + Please provide a valid phone number. + Silahkan sediakan nomor telepon yang sah. + + + The checkbox has an invalid value. + Nilai dari checkbox tidak sah. + + + Please enter a valid email address. + Silahkan masukkan alamat surel yang sah. + + + Please select a valid option. + Silahkan pilih opsi yang sah. + + + Please select a valid range. + Silahkan pilih rentang yang sah. + + + Please enter a valid week. + Silahkan masukkan minggu yang sah. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf index ab1153b8a27ff..54c126385886f 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf @@ -66,6 +66,14 @@ Account is locked. Akun terkunci. + + Too many failed login attempts, please try again later. + Terlalu banyak percobaan login yang salah, Silahkan coba lagi nanti. + + + Invalid or expired login link. + Link login salah atau sudah kadaluwarsa. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index bf4b85deefc35..40d07cf57cbb9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -330,6 +330,62 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Business Identifier Code (BIC) ini tidak terkait dengan IBAN {{ iban }}. + + This value should be valid JSON. + Nilai ini harus berisi JSON yang sah. + + + This collection should contain only unique elements. + Kumpulan ini harus mengandung elemen yang unik. + + + This value should be positive. + Nilai ini harus positif. + + + This value should be either positive or zero. + Nilai ini harus positif atau nol. + + + This value should be negative. + Nilai ini harus negatif. + + + This value should be either negative or zero. + Nilai ini harus negatif atau nol. + + + This value is not a valid timezone. + Nilai ini harus merupakan zona waktu yang sah. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Kata sandi ini telah bocor di data breach, harus tidak digunakan kembali. Silahkan gunakan kata sandi yang lain. + + + This value should be between {{ min }} and {{ max }}. + Nilai ini harus berada diantara {{ min }} dan {{ max }}. + + + This value is not a valid hostname. + Nilai ini bukan merupakan hostname yang sah. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Angka dari setiap elemen di dalam kumpulan ini harus kelipatan dari {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Nilai ini harus memenuhi setidaknya satu dari batasan berikut: + + + Each element of this collection should satisfy its own set of constraints. + Setiap elemen koleksi ini harus memenuhi batasannya sendiri. + + + This value is not a valid International Securities Identification Number (ISIN). + Nilai ini bukan merupakan International Securities Identification Number (ISIN) yang sah. + From c83d8480057e7a2d90f3b75bb82d2b4194b0e998 Mon Sep 17 00:00:00 2001 From: Ippei Sumida Date: Mon, 26 Oct 2020 16:21:26 +0900 Subject: [PATCH 116/146] Add missing translations for Japanese. --- .../Resources/translations/validators.ja.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.ja.xlf | 8 ++ .../Resources/translations/validators.ja.xlf | 12 ++ 3 files changed, 140 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf index 0db5eddbe68a6..ea2226ce4182f 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRFトークンが無効です、再送信してください。 + + This value is not a valid HTML5 color. + 有効なHTML5の色ではありません。 + + + Please enter a valid birthdate. + 有効な生年月日を入力してください。 + + + The selected choice is invalid. + 選択した値は無効です。 + + + The collection is invalid. + コレクションは無効です。 + + + Please select a valid color. + 有効な色を選択してください。 + + + Please select a valid country. + 有効な国を選択してください。 + + + Please select a valid currency. + 有効な通貨を選択してください。 + + + Please choose a valid date interval. + 有効な日付間隔を選択してください。 + + + Please enter a valid date and time. + 有効な日時を入力してください。 + + + Please enter a valid date. + 有効な日付を入力してください。 + + + Please select a valid file. + 有効なファイルを選択してください。 + + + The hidden field is invalid. + 隠しフィールドが無効です。 + + + Please enter an integer. + 整数で入力してください。 + + + Please select a valid language. + 有効な言語を選択してください。 + + + Please select a valid locale. + 有効なロケールを選択してください。 + + + Please enter a valid money amount. + 有効な金額を入力してください。 + + + Please enter a number. + 数値で入力してください。 + + + The password is invalid. + パスワードが無効です。 + + + Please enter a percentage value. + パーセント値で入力してください。 + + + The values do not match. + 値が一致しません。 + + + Please enter a valid time. + 有効な時間を入力してください。 + + + Please select a valid timezone. + 有効なタイムゾーンを選択してください。 + + + Please enter a valid URL. + 有効なURLを入力してください。 + + + Please enter a valid search term. + 有効な検索語を入力してください。 + + + Please provide a valid phone number. + 有効な電話番号を入力してください。 + + + The checkbox has an invalid value. + チェックボックスの値が無効です。 + + + Please enter a valid email address. + 有効なメールアドレスを入力してください。 + + + Please select a valid option. + 有効な値を選択してください。 + + + Please select a valid range. + 有効な範囲を選択してください。 + + + Please enter a valid week. + 有効な週を入力してください。 + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ja.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ja.xlf index 6a6b062d946c3..bdbd52fbb0503 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.ja.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ja.xlf @@ -66,6 +66,14 @@ Account is locked. アカウントはロックされています。 + + Too many failed login attempts, please try again later. + ログイン試行回数を超えました。しばらくして再度お試しください。 + + + Invalid or expired login link. + ログインリンクが有効期限切れ、もしくは無効です。 + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 8bff68b1ee90c..1a99117f930ad 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -374,6 +374,18 @@ The number of elements in this collection should be a multiple of {{ compared_value }}. 要素の数は{{ compared_value }}の倍数でなければなりません。 + + This value should satisfy at least one of the following constraints: + 以下の制約のうち少なくとも1つを満たす必要があります: + + + Each element of this collection should satisfy its own set of constraints. + コレクションの各要素は、それぞれの制約を満たす必要があります。 + + + This value is not a valid International Securities Identification Number (ISIN). + この値は有効な国際証券識別番号(ISIN)ではありません。 + From 1d09b490764263ecfcd89d78ccea87a7f4393af4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 26 Oct 2020 11:17:41 +0100 Subject: [PATCH 117/146] Disable platform checks --- .appveyor.yml | 1 - .github/composer-config.json | 1 + .travis.yml | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 86ed50c856b37..f0865f311d664 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -64,7 +64,6 @@ install: - php composer.phar config --global platform.php 5.5.9 - php composer.phar update --no-progress --ansi - php phpunit install - - break > .phpunit/phpunit-4.8-0/vendor/composer/platform_check.php test_script: - SET X=0 diff --git a/.github/composer-config.json b/.github/composer-config.json index 185292ab21cea..752047dbb681d 100644 --- a/.github/composer-config.json +++ b/.github/composer-config.json @@ -1,5 +1,6 @@ { "config": { + "platform-check": false, "preferred-install": { "symfony/form": "source", "symfony/http-kernel": "source", diff --git a/.travis.yml b/.travis.yml index 2675fe5f9c2bb..f7704d15bb2c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -312,7 +312,6 @@ install: tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty if [[ $PHP = ${MIN_PHP%.*} ]]; then export PHP=$MIN_PHP - echo '' > vendor/composer/platform_check.php echo -e "1\\n0" | xargs -I{} bash -c "tfold src/Symfony/Component/Process.sigchild{} SYMFONY_DEPRECATIONS_HELPER=weak ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8-1/phpunit --colors=always src/Symfony/Component/Process/" fi fi From 929bba668ca23921863ff26c66ec53c1c9dbdced Mon Sep 17 00:00:00 2001 From: Tavo Nieves J Date: Sun, 25 Oct 2020 11:46:36 -0500 Subject: [PATCH 118/146] [Form] Added missing Spanish translations. --- .../Resources/translations/validators.es.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.es.xlf b/src/Symfony/Component/Form/Resources/translations/validators.es.xlf index b609e53e5600a..c143e009e1938 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.es.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. El token CSRF no es válido. Por favor, pruebe a enviar nuevamente el formulario. + + This value is not a valid HTML5 color. + Este valor no es un color HTML5 válido. + + + Please enter a valid birthdate. + Por favor, ingrese una fecha de cumpleaños válida. + + + The selected choice is invalid. + La opción seleccionada no es válida. + + + The collection is invalid. + La colección no es válida. + + + Please select a valid color. + Por favor, seleccione un color válido. + + + Please select a valid country. + Por favor, seleccione un país válido. + + + Please select a valid currency. + Por favor, seleccione una moneda válida. + + + Please choose a valid date interval. + Por favor, elija un intervalo de fechas válido. + + + Please enter a valid date and time. + Por favor, ingrese una fecha y hora válidas. + + + Please enter a valid date. + Por favor, ingrese una fecha valida. + + + Please select a valid file. + Por favor, seleccione un archivo válido. + + + The hidden field is invalid. + El campo oculto no es válido. + + + Please enter an integer. + Por favor, ingrese un número entero. + + + Please select a valid language. + Por favor, seleccione un idioma válido. + + + Please select a valid locale. + Por favor, seleccione una configuración regional válida. + + + Please enter a valid money amount. + Por favor, ingrese una cantidad de dinero válida. + + + Please enter a number. + Por favor, ingrese un número. + + + The password is invalid. + La contraseña no es válida. + + + Please enter a percentage value. + Por favor, ingrese un valor porcentual. + + + The values do not match. + Los valores no coinciden. + + + Please enter a valid time. + Por favor, ingrese una hora válida. + + + Please select a valid timezone. + Por favor, seleccione una zona horaria válida. + + + Please enter a valid URL. + Por favor, ingrese una URL válida. + + + Please enter a valid search term. + Por favor, ingrese un término de búsqueda válido. + + + Please provide a valid phone number. + Por favor, proporcione un número de teléfono válido. + + + The checkbox has an invalid value. + La casilla de verificación tiene un valor inválido. + + + Please enter a valid email address. + Por favor, ingrese una dirección de correo electrónico válida. + + + Please select a valid option. + Por favor, seleccione una opción válida. + + + Please select a valid range. + Por favor, seleccione un rango válido. + + + Please enter a valid week. + Por favor, ingrese una semana válida. + From 9de3c41cc7b0a265096434734b6fb16365513100 Mon Sep 17 00:00:00 2001 From: Miro Michalicka Date: Mon, 26 Oct 2020 13:51:19 +0100 Subject: [PATCH 119/146] [Security] Add missing Slovak translations. --- .../Security/Core/Resources/translations/security.sk.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf index e6552a6a0914e..ce259df3fdee4 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf @@ -66,6 +66,14 @@ Account is locked. Účet je zablokovaný. + + Too many failed login attempts, please try again later. + Príliš mnoho neúspešných pokusov o prihlásenie. Skúste to prosím znovu neskôr. + + + Invalid or expired login link. + Neplatný alebo expirovaný odkaz na prihlásenie. + From 0abc4b30e39786bf9791dbd9da1f12ceb8c12f92 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 26 Oct 2020 14:10:06 +0100 Subject: [PATCH 120/146] [travis] Use composer 2 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f7704d15bb2c0..09cc2c0a62384 100644 --- a/.travis.yml +++ b/.travis.yml @@ -289,6 +289,7 @@ install: return fi phpenv global ${PHP/hhvm*/hhvm} + composer self-update --2 rm vendor/composer/package-versions-deprecated -Rf if [[ $PHP = 7.* ]]; then ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.6.0; composer require --dev --no-update mongodb/mongodb ~1.5.0) From 255f1e3478caf9b8e8dfb843e448074bce594949 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 26 Oct 2020 17:14:25 +0100 Subject: [PATCH 121/146] [travis] Fix location of composer home --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7704d15bb2c0..4eb58a90bfb65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,8 +71,7 @@ before_install: stty cols 120 mkdir /tmp/slapd slapd -f src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf -h ldap://localhost:3389 & - [ -d ~/.composer ] || mkdir ~/.composer - cp .github/composer-config.json ~/.composer/config.json + cp .github/composer-config.json "$(composer config home)/config.json" export PHPUNIT=$(readlink -f ./phpunit) export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" export COMPOSER_UP='composer update --no-progress --ansi' From db4658e04453c965420fb03d62bba727a16adef4 Mon Sep 17 00:00:00 2001 From: Vitalii Ekert Date: Mon, 26 Oct 2020 20:23:35 +0200 Subject: [PATCH 122/146] [Form] Add missing translations for Ukrainian (uk) --- .../Resources/translations/validators.uk.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf index 4c739face54f8..5c2d9f31ab9de 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF значення недопустиме. Будь-ласка, спробуйте відправити форму знову. + + This value is not a valid HTML5 color. + Це значення не є допустимим кольором HTML5. + + + Please enter a valid birthdate. + Будь ласка, введіть дійсну дату народження. + + + The selected choice is invalid. + Обраний варіант недійсний. + + + The collection is invalid. + Колекція недійсна. + + + Please select a valid color. + Будь ласка, оберіть дійсний колір. + + + Please select a valid country. + Будь ласка, оберіть дійсну країну. + + + Please select a valid currency. + Будь ласка, оберіть дійсну валюту. + + + Please choose a valid date interval. + Будь ласка, оберіть дійсний інтервал дати. + + + Please enter a valid date and time. + Будь ласка, введіть дійсну дату та час. + + + Please enter a valid date. + Будь ласка, введіть дійсну дату. + + + Please select a valid file. + Будь ласка, оберіть дійсний файл. + + + The hidden field is invalid. + Приховане поле недійсне. + + + Please enter an integer. + Будь ласка, введіть ціле число. + + + Please select a valid language. + Будь ласка, оберіть дійсну мову. + + + Please select a valid locale. + Будь ласка, оберіть дійсну локаль. + + + Please enter a valid money amount. + Будь ласка, введіть дійсну суму грошей. + + + Please enter a number. + Будь ласка, введіть число. + + + The password is invalid. + Пароль недійсний. + + + Please enter a percentage value. + Будь ласка, введіть процентне значення. + + + The values do not match. + Значення не збігаються. + + + Please enter a valid time. + Будь ласка, введіть дійсний час. + + + Please select a valid timezone. + Будь ласка, оберіть дійсний часовий пояс. + + + Please enter a valid URL. + Будь ласка, введіть дійсну URL-адресу. + + + Please enter a valid search term. + Будь ласка, введіть дійсний пошуковий термін. + + + Please provide a valid phone number. + Будь ласка, введіть дійсний номер телефону. + + + The checkbox has an invalid value. + Прапорець має недійсне значення. + + + Please enter a valid email address. + Будь ласка, введіть дійсну адресу електронної пошти. + + + Please select a valid option. + Будь ласка, оберіть дійсний варіант. + + + Please select a valid range. + Будь ласка, оберіть дійсний діапазон. + + + Please enter a valid week. + Будь ласка, введіть дійсний тиждень. + From 969603b9c7d17f8be23229b8e34c86fdba3a4f90 Mon Sep 17 00:00:00 2001 From: Vitalii Ekert Date: Mon, 26 Oct 2020 20:26:01 +0200 Subject: [PATCH 123/146] [Security] Add missing translations for Ukrainian (uk) --- .../Security/Core/Resources/translations/security.uk.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.uk.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.uk.xlf index 79721212068db..5cf708f967479 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.uk.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.uk.xlf @@ -66,6 +66,14 @@ Account is locked. Обліковий запис заблоковано. + + Too many failed login attempts, please try again later. + Забагато невдалих спроб входу. Будь ласка, спробуйте пізніше. + + + Invalid or expired login link. + Посилання для входу недійсне, або термін його дії закінчився. + From 8aa7b7235eef64abe4fc7e70ec9efa8f37365994 Mon Sep 17 00:00:00 2001 From: Vitalii Ekert Date: Mon, 26 Oct 2020 20:27:17 +0200 Subject: [PATCH 124/146] [Validator] Add missing translations for Ukrainian (uk) --- .../Validator/Resources/translations/validators.uk.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index 688e11fbe929c..7ea908e75706d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -382,6 +382,10 @@ Each element of this collection should satisfy its own set of constraints. Кожен елемент цієї колекції повинен задовольняти власному набору обмежень. + + This value is not a valid International Securities Identification Number (ISIN). + Це значення не є дійсним міжнародним ідентифікаційним номером цінних паперів (ISIN). + From 6e386e9c4c275ce7b7c8c069e3d9775ce1b5fe2b Mon Sep 17 00:00:00 2001 From: Vitalii Ekert Date: Mon, 26 Oct 2020 20:31:48 +0200 Subject: [PATCH 125/146] [Form] Fix wrong translations for Ukrainian (uk) --- .../Component/Form/Resources/translations/validators.uk.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf index 4c739face54f8..ad20fcdfd21d2 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf @@ -8,11 +8,11 @@ The uploaded file was too large. Please try to upload a smaller file. - Завантажений файл занадто великий. Будь-ласка, спробуйте завантажити файл меншого розміру. + Завантажений файл занадто великий. Будь ласка, спробуйте завантажити файл меншого розміру. The CSRF token is invalid. Please try to resubmit the form. - CSRF значення недопустиме. Будь-ласка, спробуйте відправити форму знову. + CSRF значення недопустиме. Будь ласка, спробуйте відправити форму знову. From d29cd19a3daed9732acb1b90be56bcf2b4347e46 Mon Sep 17 00:00:00 2001 From: Amirreza Shafaat Date: Mon, 26 Oct 2020 20:24:24 +0330 Subject: [PATCH 126/146] [Form, Security, Validator] Add missing Persian translations (fa_IR) --- .../Resources/translations/validators.fa.xlf | 126 +++++++++++++++++- .../Resources/translations/security.fa.xlf | 8 ++ .../Resources/translations/validators.fa.xlf | 56 ++++++++ 3 files changed, 187 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf index 1c784c24a0e2d..1bbe090f34472 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf @@ -4,15 +4,135 @@ This form should not contain extra fields. - این فرم نباید شامل فیلد اضافه ای باشد. + این فرم نباید شامل فیلدهای اضافی باشد. The uploaded file was too large. Please try to upload a smaller file. - فایل بارگذاری شده بسیار بزرگ می باشد. لطفا فایل کوچکتری را بارگذاری نمایید. + فایل بارگذاری‌شده بسیار بزرگ است. لطفاً فایل کوچک‌تری را بارگذاری نمایید. The CSRF token is invalid. Please try to resubmit the form. - توکن CSRF نامعتبر می باشد. لطفا فرم را مجددا ارسال نمایید. + توکن CSRF نامعتبر است. لطفاً فرم را مجدداً ارسال نمایید. + + + This value is not a valid HTML5 color. + این مقدار یک رنگ معتبر HTML5 نیست. + + + Please enter a valid birthdate. + لطفاً یک تاریخ تولد معتبر وارد نمایید. + + + The selected choice is invalid. + گزینه‌ی انتخاب‌شده نامعتبر است + + + The collection is invalid. + این مجموعه نامعتبر است. + + + Please select a valid color. + لطفاً یک رنگ معتبر انتخاب کنید. + + + Please select a valid country. + لطفاً یک کشور معتبر انتخاب کنید. + + + Please select a valid currency. + لطفاً یک واحد پولی معتبر انتخاب کنید. + + + Please choose a valid date interval. + لطفاً یک بازه‌ی زمانی معتبر انتخاب کنید. + + + Please enter a valid date and time. + لطفاً یک تاریخ و زمان معتبر وارد کنید. + + + Please enter a valid date. + لطفاً یک تاریخ معتبر وارد کنید. + + + Please select a valid file. + لطفاً یک فایل معتبر انتخاب کنید. + + + The hidden field is invalid. + فیلد مخفی نامعتبر است. + + + Please enter an integer. + لطفاً یک عدد صحیح وارد کنید. + + + Please select a valid language. + لطفاً یک زبان معتبر انتخاب کنید. + + + Please select a valid locale. + لطفاً یک جغرافیای (locale) معتبر انتخاب کنید. + + + Please enter a valid money amount. + لطفاً یک مقدار پول معتبر وارد کنید. + + + Please enter a number. + لطفاً یک عدد وارد کنید. + + + The password is invalid. + رمزعبور نامعتبر است. + + + Please enter a percentage value. + لطفاً یک درصد معتبر وارد کنید. + + + The values do not match. + مقادیر تطابق ندارند. + + + Please enter a valid time. + لطفاً یک زمان معتبر وارد کنید. + + + Please select a valid timezone. + لطفاً یک منطقه‌زمانی معتبر وارد کنید. + + + Please enter a valid URL. + لطفاً یک URL معتبر وارد کنید. + + + Please enter a valid search term. + لطفاً یک عبارت جستجوی معتبر وارد کنید. + + + Please provide a valid phone number. + لطفاً یک شماره تلفن معتبر وارد کنید. + + + The checkbox has an invalid value. + کادر انتخاب (checkbox) دارای مقداری نامعتبر است. + + + Please enter a valid email address. + لطفاً یک آدرس رایانامه‌ی معتبر وارد کنید. + + + Please select a valid option. + لطفاً یک گزینه‌ی معتبر انتخاب کنید. + + + Please select a valid range. + لطفاً یک محدوده‌ی معتبر انتخاب کنید. + + + Please enter a valid week. + لطفاً یک هفته‌ی معتبر وارد کنید. diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.fa.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.fa.xlf index b461e3fe4da7b..467d481b65e18 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.fa.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.fa.xlf @@ -66,6 +66,14 @@ Account is locked. حساب کاربری قفل گردیده است. + + Too many failed login attempts, please try again later. + تلاش‌های ناموفق زیادی برای ورود صورت گرفته است، لطفاً بعداً دوباره تلاش کنید. + + + Invalid or expired login link. + لینک ورود نامعتبر یا تاریخ‌گذشته است. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index c0b42096b5bd7..688f394eab404 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -330,6 +330,62 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. این(BIC) با IBAN ارتباطی ندارد. + + This value should be valid JSON. + این مقدار باید یک JSON معتبر باشد. + + + This collection should contain only unique elements. + این مجموعه باید تنها شامل عناصر یکتا باشد. + + + This value should be positive. + این مقدار باید مثبت باشد. + + + This value should be either positive or zero. + این مقدار باید مثبت یا صفر باشد. + + + This value should be negative. + این مقدار باید منفی باشد. + + + This value should be either negative or zero. + این مقدار باید منفی یا صفر باشد. + + + This value is not a valid timezone. + این مقدار یک منطقه‌زمانی (timezone) معتبر نیست. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + این رمزعبور در یک رخنه‌ی اطلاعاتی نشت کرده است. لطفاً از یک رمزعبور دیگر استفاده کنید. + + + This value should be between {{ min }} and {{ max }}. + این مقدار باید بین {{ min }} و {{ max }} باشد + + + This value is not a valid hostname. + این مقدار یک hostname معتبر نیست. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + تعداد عناصر این مجموعه باید ضریبی از {{ compared_value }} باشد. + + + This value should satisfy at least one of the following constraints: + این مقدار باید حداقل یکی از محدودیت‌های زیر را ارضا کند: + + + Each element of this collection should satisfy its own set of constraints. + هر یک از عناصر این مجموعه باید دسته محدودیت‌های خودش را ارضا کند. + + + This value is not a valid International Securities Identification Number (ISIN). + این مقدار یک شماره شناسایی بین‌المللی اوراق بهادار (ISIN) معتبر نیست. + From 7b91af855a069f240e3f0852ca2cafabec68b0ac Mon Sep 17 00:00:00 2001 From: Miro Michalicka Date: Mon, 26 Oct 2020 14:05:07 +0100 Subject: [PATCH 127/146] [Validator] Add missing Slovak translations. --- .../Resources/translations/validators.sk.xlf | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index a161ddbfe8845..a0c55ea6db146 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -366,6 +366,26 @@ This value should be between {{ min }} and {{ max }}. Táto hodnota by mala byť medzi {{ min }} a {{ max }}. + + This value is not a valid hostname. + Táto hodnota nie je platný hostname. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Počet prvkov v tejto kolekcii musí byť násobok {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Táto hodnota musí spĺňať aspoň jedno z nasledujúcich obmedzení: + + + Each element of this collection should satisfy its own set of constraints. + Každý prvok v tejto kolekcii musí spĺňať svoje vlastné obmedzenia. + + + This value is not a valid International Securities Identification Number (ISIN). + Táto hodnota nie je platné medzinárodné označenie cenného papiera (ISIN). + From 676b8080a5312bd8296b318e67c1ab6b40315f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 25 Oct 2020 20:35:54 +0100 Subject: [PATCH 128/146] Fix transient tests --- .../Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php | 3 +++ .../Component/VarDumper/Tests/Dumper/ServerDumperTest.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index 582b62501f323..b1d1df2fc317a 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -161,6 +161,9 @@ public function testItReceivesSignals() $signalTime = microtime(true); $timedOutTime = time() + 10; + // wait for worker started and registered the signal handler + usleep(100 * 1000); // 100ms + // immediately after the process has started "booted", kill it $process->signal(15); diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php index c52ec191d8b87..6999809fa97c6 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php @@ -89,6 +89,6 @@ private function getServerProcess(): Process 'VAR_DUMPER_SERVER' => self::VAR_DUMPER_SERVER, ]); - return $process->setTimeout(9); + return $process->setTimeout('\\' === \DIRECTORY_SEPARATOR ? 19 : 9); } } From 7cf4ca6f8398296551065d8ccf328709e18abd0e Mon Sep 17 00:00:00 2001 From: Johan Date: Sun, 25 Oct 2020 20:02:01 +0100 Subject: [PATCH 129/146] 38737 add missing dutch translation --- .../Security/Core/Resources/translations/security.nl.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.nl.xlf index 8969e9ef8ca69..b002c75e6590d 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.nl.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.nl.xlf @@ -66,6 +66,14 @@ Account is locked. Account is geblokkeerd. + + Too many failed login attempts, please try again later. + Te veel onjuiste inlogpogingen, probeer het later nogmaals. + + + Invalid or expired login link. + Ongeldige of verlopen inloglink. + From 8cf60c4ab78e6450af04d92973da2bba83b5db43 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Oct 2020 09:50:57 +0100 Subject: [PATCH 130/146] [ProxyManager] use "composer/package-versions-deprecated" instead of "ocramius/package-versions" --- src/Symfony/Bridge/ProxyManager/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 1c33be86ca084..b34def8465dd2 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=7.1.3", + "composer/package-versions-deprecated": "^1.8", "symfony/dependency-injection": "^4.0|^5.0", "ocramius/proxy-manager": "~2.1" }, From 25a7333e62da52ba5ef2f747f7c2a57db448affa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 26 Oct 2020 15:36:43 +0100 Subject: [PATCH 131/146] Display php info for extra versions in travis --- .travis.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7704d15bb2c0..be425e45fd54a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -174,6 +174,8 @@ before_install: for PHP in $TRAVIS_PHP_VERSION $php_extra; do export PHP=$PHP phpenv global $PHP + composer self-update + composer self-update --2 INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini if [[ $PHP = 5.* ]]; then tfold ext.apcu tpecl apcu-4.0.11 apcu.so $INI @@ -278,7 +280,16 @@ install: - | # phpinfo - php -i + phpinfo() { + phpenv global $1 + php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;' + php -i + } + export -f phpinfo + + for PHP in $TRAVIS_PHP_VERSION $php_extra; do + tfold $PHP phpinfo $PHP + done - | run_tests () { From 9facb1a11a2564f04f0ab97bdefb45e67eb02015 Mon Sep 17 00:00:00 2001 From: Ahmed Eben Hassine Date: Mon, 26 Oct 2020 20:40:26 +0100 Subject: [PATCH 132/146] [Form, Security, Validator] Add missing Turkish translations (tr) --- .../Resources/translations/validators.tr.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.tr.xlf | 8 ++ .../Resources/translations/validators.tr.xlf | 56 ++++++++ 3 files changed, 184 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf index 70e8541ed909c..d1ddc1d0ef33d 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF fişi geçersiz. Formu tekrar göndermeyi deneyin. + + This value is not a valid HTML5 color. + Bu değer, geçerli bir HTML5 rengi değil. + + + Please enter a valid birthdate. + Lütfen geçerli bir doğum tarihi girin. + + + The selected choice is invalid. + Seçilen seçim geçersiz. + + + The collection is invalid. + Koleksiyon geçersiz. + + + Please select a valid color. + Lütfen geçerli bir renk seçin. + + + Please select a valid country. + Lütfen geçerli bir ülke seçin. + + + Please select a valid currency. + Lütfen geçerli bir para birimi seçin. + + + Please choose a valid date interval. + Lütfen geçerli bir tarih aralığı seçin. + + + Please enter a valid date and time. + Lütfen geçerli bir tarih ve saat girin. + + + Please enter a valid date. + Lütfen geçerli bir tarih giriniz. + + + Please select a valid file. + Lütfen geçerli bir dosya seçin. + + + The hidden field is invalid. + Gizli alan geçersiz. + + + Please enter an integer. + Lütfen bir tam sayı girin. + + + Please select a valid language. + Lütfen geçerli bir dil seçin. + + + Please select a valid locale. + Lütfen geçerli bir yerel ayar seçin. + + + Please enter a valid money amount. + Lütfen geçerli bir para tutarı girin. + + + Please enter a number. + Lütfen bir numara giriniz. + + + The password is invalid. + Şifre geçersiz. + + + Please enter a percentage value. + Lütfen bir yüzde değeri girin. + + + The values do not match. + Değerler eşleşmiyor. + + + Please enter a valid time. + Lütfen geçerli bir zaman girin. + + + Please select a valid timezone. + Lütfen geçerli bir saat dilimi seçin. + + + Please enter a valid URL. + Lütfen geçerli bir giriniz URL. + + + Please enter a valid search term. + Lütfen geçerli bir arama terimi girin. + + + Please provide a valid phone number. + lütfen geçerli bir telefon numarası sağlayın. + + + The checkbox has an invalid value. + Onay kutusunda geçersiz bir değer var. + + + Please enter a valid email address. + Lütfen geçerli bir e-posta adresi girin. + + + Please select a valid option. + Lütfen geçerli bir seçenek seçin. + + + Please select a valid range. + Lütfen geçerli bir aralık seçin. + + + Please enter a valid week. + Lütfen geçerli bir hafta girin. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.tr.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.tr.xlf index 68c44213d18c3..3854590cc1e49 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.tr.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.tr.xlf @@ -66,6 +66,14 @@ Account is locked. Hesap kilitlenmiş. + + Too many failed login attempts, please try again later. + Çok fazla başarısız giriş denemesi, lütfen daha sonra tekrar deneyin. + + + Invalid or expired login link. + Geçersiz veya süresi dolmuş oturum açma bağlantısı. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 76de2214e6bcb..6c39fac818238 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -330,6 +330,62 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Bu İşletme Tanımlayıcı Kodu (BIC), IBAN {{ iban }} ile ilişkili değildir. + + This value should be valid JSON. + Bu değer için geçerli olmalıdır JSON. + + + This collection should contain only unique elements. + Bu grup yalnızca benzersiz öğeler içermelidir. + + + This value should be positive. + Bu değer pozitif olmalı. + + + This value should be either positive or zero. + Bu değer pozitif veya sıfır olmalıdır. + + + This value should be negative. + Bu değer negatif olmalıdır. + + + This value should be either negative or zero. + Bu değer, negatif veya sıfır olmalıdır. + + + This value is not a valid timezone. + Bu değer, geçerli bir saat dilimi değil. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Bu parola, bir veri ihlali nedeniyle sızdırılmıştır ve kullanılmamalıdır. Lütfen başka bir şifre kullanın. + + + This value should be between {{ min }} and {{ max }}. + Bu değer arasında olmalıdır {{ min }} ve {{ max }}. + + + This value is not a valid hostname. + Bu değer, geçerli bir ana bilgisayar adı değil. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Bu gruptaki öğe sayısı birden fazla olmalıdır {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Bu değer aşağıdaki kısıtlamalardan birini karşılamalıdır: + + + Each element of this collection should satisfy its own set of constraints. + Bu gruptaki her öğe kendi kısıtlamalarını karşılamalıdır. + + + This value is not a valid International Securities Identification Number (ISIN). + Bu değer geçerli bir Uluslararası Menkul Kıymetler Kimlik Numarası değil (ISIN). + From bde427a3033849b49f0fc5ce5fd360224b7e0347 Mon Sep 17 00:00:00 2001 From: Albion Bame Date: Mon, 26 Oct 2020 20:44:18 +0100 Subject: [PATCH 133/146] [Translation] added missing Albanian translations --- .../Resources/translations/validators.sq.xlf | 139 ++++++++++++++++++ .../Resources/translations/security.sq.xlf | 79 ++++++++++ .../Resources/translations/validators.sq.xlf | 56 +++++++ 3 files changed, 274 insertions(+) create mode 100644 src/Symfony/Component/Form/Resources/translations/validators.sq.xlf create mode 100644 src/Symfony/Component/Security/Core/Resources/translations/security.sq.xlf diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf new file mode 100644 index 0000000000000..3224f6e38ad0a --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf @@ -0,0 +1,139 @@ + + + + + + This form should not contain extra fields. + Kjo formë nuk duhet të përmbajë fusha shtesë. + + + The uploaded file was too large. Please try to upload a smaller file. + Skedari i ngarkuar ishte shumë i madh. Ju lutemi provoni të ngarkoni një skedar më të vogël. + + + The CSRF token is invalid. Please try to resubmit the form. + Vlera CSRF është e pavlefshme. Ju lutemi provoni të ridërgoni formën. + + + This value is not a valid HTML5 color. + Kjo vlerë nuk është një ngjyrë e vlefshme HTML5. + + + Please enter a valid birthdate. + Ju lutemi shkruani një datëlindje të vlefshme. + + + The selected choice is invalid. + Opsioni i zgjedhur është i pavlefshëm. + + + The collection is invalid. + Koleksioni është i pavlefshëm. + + + Please select a valid color. + Ju lutemi zgjidhni një ngjyrë të vlefshme. + + + Please select a valid country. + Ju lutemi zgjidhni një shtet të vlefshëm. + + + Please select a valid currency. + Ju lutemi zgjidhni një monedhë të vlefshme. + + + Please choose a valid date interval. + Ju lutemi zgjidhni një interval të vlefshëm të datës. + + + Please enter a valid date and time. + Ju lutemi shkruani një datë dhe orë të vlefshme. + + + Please enter a valid date. + Ju lutemi shkruani një datë të vlefshme. + + + Please select a valid file. + Ju lutemi zgjidhni një skedar të vlefshëm. + + + The hidden field is invalid. + Fusha e fshehur është e pavlefshme. + + + Please enter an integer. + Ju lutemi shkruani një numër të plotë. + + + Please select a valid language. + Please select a valid language. + + + Please select a valid locale. + Ju lutemi zgjidhni një lokale të vlefshme. + + + Please enter a valid money amount. + Ju lutemi shkruani një shumë të vlefshme parash. + + + Please enter a number. + Ju lutemi shkruani një numër. + + + The password is invalid. + Fjalëkalimi është i pavlefshëm. + + + Please enter a percentage value. + Ju lutemi shkruani një vlerë përqindjeje. + + + The values do not match. + Vlerat nuk përputhen. + + + Please enter a valid time. + Ju lutemi shkruani një kohë të vlefshme. + + + Please select a valid timezone. + Ju lutemi zgjidhni një zonë kohore të vlefshme. + + + Please enter a valid URL. + Ju lutemi shkruani një URL të vlefshme. + + + Please enter a valid search term. + Ju lutemi shkruani një term të vlefshëm kërkimi. + + + Please provide a valid phone number. + Ju lutemi jepni një numër telefoni të vlefshëm. + + + The checkbox has an invalid value. + Kutia e zgjedhjes ka një vlerë të pavlefshme. + + + Please enter a valid email address. + Ju lutemi shkruani një adresë të vlefshme emaili. + + + Please select a valid option. + Ju lutemi zgjidhni një opsion të vlefshëm. + + + Please select a valid range. + Ju lutemi zgjidhni një diapazon të vlefshëm. + + + Please enter a valid week. + Ju lutemi shkruani një javë të vlefshme. + + + + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.sq.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.sq.xlf new file mode 100644 index 0000000000000..4f4bc6d4cbc61 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.sq.xlf @@ -0,0 +1,79 @@ + + + + + + An authentication exception occurred. + Ndodhi një problem në autentikim. + + + Authentication credentials could not be found. + Kredencialet e autentikimit nuk mund të gjendeshin. + + + Authentication request could not be processed due to a system problem. + Kërkesa për autentikim nuk mund të përpunohej për shkak të një problemi në sistem. + + + Invalid credentials. + Kredenciale të pavlefshme. + + + Cookie has already been used by someone else. + Cookie është përdorur tashmë nga dikush tjetër. + + + Not privileged to request the resource. + Nuk është i privilegjuar të kërkojë burimin. + + + Invalid CSRF token. + Identifikues i pavlefshëm CSRF. + + + Digest nonce has expired. + Numeri një perdorimësh i verifikimit Digest ka skaduar. + + + No authentication provider found to support the authentication token. + Asnjë ofrues i vërtetimit nuk u gjet që të mbështesë simbolin e vërtetimit. + + + No session available, it either timed out or cookies are not enabled. + Nuk ka asnjë sesion të vlefshëm, i ka skaduar koha ose cookies nuk janë aktivizuar. + + + No token could be found. + Asnjë simbol identifikimi nuk mund të gjendej. + + + Username could not be found. + Emri i përdoruesit nuk mund të gjendej. + + + Account has expired. + Llogaria ka skaduar. + + + Credentials have expired. + Kredencialet kanë skaduar. + + + Account is disabled. + Llogaria është çaktivizuar. + + + Account is locked. + Llogaria është e kyçur. + + + Too many failed login attempts, please try again later. + Shumë përpjekje të dështuara autentikimi, provo përsëri më vonë. + + + Invalid or expired login link. + Link hyrje i pavlefshëm ose i skaduar. + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index 569ebca47f02e..6c0acb9fdf43f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -330,6 +330,62 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Ky Kod Identifikues i Biznesit (BIC) nuk është i lidhur me IBAN {{ iban }}. + + This value should be valid JSON. + Kjo vlerë duhet të jetë JSON i vlefshëm. + + + This collection should contain only unique elements. + Ky koleksion duhet të përmbajë vetëm elementë unikë. + + + This value should be positive. + Kjo vlerë duhet të jetë pozitive. + + + This value should be either positive or zero. + Kjo vlerë duhet të jetë pozitive ose zero. + + + This value should be negative. + Kjo vlerë duhet të jetë negative. + + + This value should be either negative or zero. + Kjo vlerë duhet të jetë negative ose zero. + + + This value is not a valid timezone. + Kjo vlerë nuk është një zonë e vlefshme kohore. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Ky fjalëkalim është zbuluar në një shkelje të të dhënave, nuk duhet të përdoret. Ju lutemi përdorni një fjalëkalim tjetër. + + + This value should be between {{ min }} and {{ max }}. + Kjo vlerë duhet të jetë ndërmjet {{ min }} dhe {{ max }}. + + + This value is not a valid hostname. + Kjo vlerë nuk është një emër i vlefshëm hosti. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Numri i elementeve në këtë koleksion duhet të jetë një shumëfish i {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Kjo vlerë duhet të plotësojë të paktën njërën nga kufizimet e mëposhtme: + + + Each element of this collection should satisfy its own set of constraints. + Secili element i këtij koleksioni duhet të përmbushë kufizimet e veta. + + + This value is not a valid International Securities Identification Number (ISIN). + Kjo vlerë nuk është një numër i vlefshëm identifikues ndërkombëtar i sigurisë (ISIN). + From b6ae4858b91342f0b3186f0885d60a7540138bf3 Mon Sep 17 00:00:00 2001 From: Randy Geraads Date: Sun, 25 Oct 2020 12:15:32 +0100 Subject: [PATCH 134/146] [DI] Fix Preloader exception when preloading a class with an unknown parent/interface --- .../DependencyInjection/Dumper/Preloader.php | 2 +- .../Tests/Dumper/PreloaderTest.php | 14 ++++++++++++++ .../Fixtures/Preload/DummyWithInterface.php | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/DummyWithInterface.php diff --git a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php index 1e0b6919fd1fe..125a555fdaf7d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php @@ -87,7 +87,7 @@ private static function doPreload(string $class, array &$preloaded): void self::preloadType($m->getReturnType(), $preloaded); } - } catch (\ReflectionException $e) { + } catch (\Throwable $e) { // ignore missing classes } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php index a9b3242031537..ff70bb75ea08c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PreloaderTest.php @@ -34,6 +34,20 @@ public function testPreload() self::assertTrue(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\C', false)); } + /** + * @requires PHP 7.4 + */ + public function testPreloadSkipsNonExistingInterface() + { + $r = new \ReflectionMethod(Preloader::class, 'doPreload'); + $r->setAccessible(true); + + $preloaded = []; + + $r->invokeArgs(null, ['Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\DummyWithInterface', &$preloaded]); + self::assertFalse(class_exists('Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\DummyWithInterface', false)); + } + /** * @requires PHP 8 */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/DummyWithInterface.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/DummyWithInterface.php new file mode 100644 index 0000000000000..1c1b0d20addd4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Preload/DummyWithInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload; + +final class DummyWithInterface implements \NonExistentDummyInterface +{ +} From bf13887898e2c17088ce5968cd731c58dc28c33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Oct 2020 08:55:05 +0100 Subject: [PATCH 135/146] [HttpKernel] HttpKernelBrowser: don't set a default Accept header --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../Component/HttpKernel/HttpKernelBrowser.php | 5 ++++- .../HttpKernel/Tests/HttpKernelBrowserTest.php | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 364b8a67fc05f..db2821334323d 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * Allowed adding attributes on controller arguments that will be passed to argument resolvers. * kernels implementing the `ExtensionInterface` will now be auto-registered to the container * added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%` + * do not set a default `Accept` HTTP header when using `HttpKernelBrowser` 5.1.0 ----- diff --git a/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php b/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php index c1f5b4c922d32..554585fb9c251 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php +++ b/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php @@ -130,7 +130,10 @@ protected function getHandleScript() */ protected function filterRequest(DomRequest $request) { - $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent()); + $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $server = $request->getServer(), $request->getContent()); + if (!isset($server['HTTP_ACCEPT'])) { + $httpRequest->headers->remove('Accept'); + } foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) { $httpRequest->files->set($key, $value); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php index 4d4fe5ae72306..b64924745b25e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php @@ -179,4 +179,15 @@ public function testUploadedFileWhenSizeExceedsUploadMaxFileSize() unlink($source); } + + public function testAcceptHeaderNotSet() + { + $client = new HttpKernelBrowser(new TestHttpKernel()); + + $client->request('GET', '/'); + $this->assertFalse($client->getRequest()->headers->has('Accept')); + + $client->request('GET', '/', [], [], ['HTTP_ACCEPT' => 'application/ld+json']); + $this->assertSame('application/ld+json', $client->getRequest()->headers->get('Accept')); + } } From 4b36736e91700aa4238920b56af42edbfebe081a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Oct 2020 11:05:03 +0100 Subject: [PATCH 136/146] minor #38838 [ProxyManager] use "composer/package-versions-deprecated" instead of "ocramius/package-versions" (nicolas-grekas) This PR was merged into the 4.4 branch. Discussion ---------- [ProxyManager] use "composer/package-versions-deprecated" instead of "ocramius/package-versions" | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - As highlighted by our CI, `ocramius/proxy-manager` cannot be installed on PHP 7.3 using composer 2 because of broken versioning policies: ![image](https://user-images.githubusercontent.com/243674/97278564-37e73080-183a-11eb-885c-7b3cc07c26af.png) Fortunately, the package that causes all this mess (`ocramius/package-versions`) has been forked precisely to work around these broken policies. Requiring this fork allows resolving the dependencies properly. Commits ------- 8cf60c4ab7 [ProxyManager] use "composer/package-versions-deprecated" instead of "ocramius/package-versions" --- src/Symfony/Bridge/ProxyManager/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 09c390db09030..492a1e1df6fe1 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": "^5.5.9|>=7.0.8", + "composer/package-versions-deprecated": "^1.8", "symfony/dependency-injection": "~3.4|~4.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0" }, From de01eeae0337997eec5c45e5452fba763a3d68c3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Oct 2020 13:25:07 +0100 Subject: [PATCH 137/146] Fix CI --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd70410cc0c2c..fa9e74188ca1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -287,7 +287,7 @@ install: export -f phpinfo for PHP in $TRAVIS_PHP_VERSION $php_extra; do - tfold $PHP phpinfo $PHP + tfold phpinfo phpinfo $PHP done - | @@ -299,7 +299,6 @@ install: return fi phpenv global ${PHP/hhvm*/hhvm} - composer self-update --2 rm vendor/composer/package-versions-deprecated -Rf if [[ $PHP = 7.* ]]; then ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.6.0; composer require --dev --no-update mongodb/mongodb ~1.5.0) From 57c986a441661410c4d46b6e4543a342109b9052 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Oct 2020 14:17:00 +0100 Subject: [PATCH 138/146] Fix CI --- .github/patch-types.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/patch-types.php b/.github/patch-types.php index 46c6980dab4a2..311e9e7ee40b4 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -5,7 +5,7 @@ exit(1); } -require __DIR__.'/../.phpunit/phpunit-8.3-0/vendor/autoload.php'; +require __DIR__.'/../.phpunit/phpunit/vendor/autoload.php'; file_put_contents(__DIR__.'/../vendor/autoload.php', preg_replace('/^return (Composer.*);/m', <<<'EOTXT' $loader = \1; From 7af4fe989ab2a140f9f81e067164bf4bba43d4ca Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 27 Oct 2020 15:11:24 +0100 Subject: [PATCH 139/146] [Form] Some minor teaks for Swedish --- .../Form/Resources/translations/validators.sv.xlf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf index dff88e98f1041..43e925628a488 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf @@ -48,11 +48,11 @@ Please enter a valid date and time. - Ange datum och tid. + Ange ett giltigt datum och tid. Please enter a valid date. - Ange ett datum. + Ange ett giltigt datum. Please select a valid file. @@ -100,7 +100,7 @@ Please select a valid timezone. - Välj tidszon. + Välj en tidszon. Please enter a valid URL. @@ -132,7 +132,7 @@ Please enter a valid week. - Ange en vecka. + Ange en giltig vecka. From 92e0b3c9b26da40b1aacea26e678a82e9de91ab0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Oct 2020 14:09:15 +0100 Subject: [PATCH 140/146] Fix CI for 3.4 --- .travis.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index fa9e74188ca1c..8a02ce10d5e13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,14 +78,6 @@ before_install: export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) find ~/.phpenv -name xdebug.ini -delete - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then - composer () { - $HOME/.phpenv/versions/7.1/bin/php $HOME/.phpenv/versions/7.1/bin/composer config platform.php $(echo ' =$SYMFONY_VERSION" fi - composer global require --no-progress --no-scripts --no-plugins symfony/flex + if [[ ! $TRAVIS_PHP_VERSION = 5.* ]]; then + composer global require --no-progress --no-scripts --no-plugins symfony/flex + fi - | # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one @@ -304,11 +298,7 @@ install: ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; composer config platform.ext-mongodb 1.6.0; composer require --dev --no-update mongodb/mongodb ~1.5.0) fi tfold 'composer update' $COMPOSER_UP - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then - tfold 'phpunit install' 'composer global remove symfony/flex && ./phpunit install && composer global require --no-progress --no-scripts --no-plugins symfony/flex' - else - tfold 'phpunit install' ./phpunit install - fi + tfold 'phpunit install' ./phpunit install if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" elif [[ $deps = low ]]; then From 37b1faec8c8f2ad29591fcba5297c5f99e401e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 27 Oct 2020 16:32:21 +0100 Subject: [PATCH 141/146] [Console] Register signal handling only for commands implemeting SignalableCommandInterface Actually, it does not make sens to listen all signals for all commands. This commit also add more test for this part of code. --- src/Symfony/Component/Console/Application.php | 35 +++++----- .../Console/Tests/ApplicationTest.php | 64 +++++++++++++++++++ 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 0efccdb103002..cdb5a81d25a26 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -286,23 +286,6 @@ public function doRun(InputInterface $input, OutputInterface $output) $command = $this->find($alternative); } - if ($this->dispatcher && $this->signalRegistry) { - foreach ($this->signalsToDispatchEvent as $signal) { - $event = new ConsoleSignalEvent($command, $input, $output, $signal); - - $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) { - $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); - - // No more handlers, we try to simulate PHP default behavior - if (!$hasNext) { - if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) { - exit(0); - } - } - }); - } - } - $this->runningCommand = $command; $exitCode = $this->doRunCommand($command, $input, $output); $this->runningCommand = null; @@ -961,6 +944,24 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI if (!$this->signalRegistry) { throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } + + if ($this->dispatcher) { + foreach ($this->signalsToDispatchEvent as $signal) { + $event = new ConsoleSignalEvent($command, $input, $output, $signal); + + $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) { + $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + + // No more handlers, we try to simulate PHP default behavior + if (!$hasNext) { + if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) { + exit(0); + } + } + }); + } + } + foreach ($command->getSubscribedSignals() as $signal) { $this->signalRegistry->register($signal, [$command, 'handleSignal']); } diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 88631e0b6ea49..4141920965ee8 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Command\SignalableCommandInterface; use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass; use Symfony\Component\Console\Event\ConsoleCommandEvent; @@ -1808,6 +1809,39 @@ public function testCommandNameMismatchWithCommandLoaderKeyThrows() $app->setCommandLoader($loader); $app->get('test'); } + + /** + * @requires extension pcntl + */ + public function testSignal() + { + $command = new SignableCommand(); + + $dispatcherCalled = false; + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('console.signal', function () use (&$dispatcherCalled) { + $dispatcherCalled = true; + }); + + $application = new Application(); + $application->setAutoExit(false); + $application->setDispatcher($dispatcher); + $application->setSignalsToDispatchEvent(SIGALRM); + $application->add($command); + + $this->assertFalse($command->signaled); + $this->assertFalse($dispatcherCalled); + + $this->assertSame(0, $application->run(new ArrayInput(['signal']))); + $this->assertFalse($command->signaled); + $this->assertFalse($dispatcherCalled); + + $command->loop = 100000; + pcntl_alarm(1); + $this->assertSame(1, $application->run(new ArrayInput(['signal']))); + $this->assertTrue($command->signaled); + $this->assertTrue($dispatcherCalled); + } } class CustomApplication extends Application @@ -1865,3 +1899,33 @@ public function isEnabled(): bool return false; } } + +class SignableCommand extends Command implements SignalableCommandInterface +{ + public $signaled = false; + public $loop = 100; + + protected static $defaultName = 'signal'; + + public function getSubscribedSignals(): array + { + return [SIGALRM]; + } + + public function handleSignal(int $signal): void + { + $this->signaled = true; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + for ($i = 0; $i < $this->loop; ++$i) { + usleep(100); + if ($this->signaled) { + return 1; + } + } + + return 0; + } +} From 7bb288e9564b59c2ea3ade720ff65b0ac98f92ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 25 Oct 2020 21:39:45 +0100 Subject: [PATCH 142/146] Fix transient tests --- .../Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php index 8f76750d4446c..05c6340b6aaa5 100644 --- a/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php @@ -46,6 +46,7 @@ protected function setUp(): void /** * @dataProvider provideCreateLoginLinkData + * @group time-sensitive */ public function testCreateLoginLink($user, array $extraProperties) { From 952df248d02d9005907430bee885b777154e7f40 Mon Sep 17 00:00:00 2001 From: fd6130 Date: Wed, 28 Oct 2020 01:54:07 +0800 Subject: [PATCH 143/146] Missing translations for Chinese (zh_CN) #38732 --- .../translations/validators.zh_CN.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.zh_CN.xlf | 8 ++ .../translations/validators.zh_CN.xlf | 52 ++++++++ 3 files changed, 180 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf index 8bdf7fb5ca0bc..3106db2bd97b7 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF 验证符无效, 请重新提交. + + This value is not a valid HTML5 color. + 该数值不是个有效的 HTML5 颜色。 + + + Please enter a valid birthdate. + 请输入有效的生日日期。 + + + The selected choice is invalid. + 所选的选项无效。 + + + The collection is invalid. + 集合无效。 + + + Please select a valid color. + 请选择有效的颜色。 + + + Please select a valid country. + 请选择有效的国家。 + + + Please select a valid currency. + 请选择有效的货币。 + + + Please choose a valid date interval. + 请选择有效的日期间隔。 + + + Please enter a valid date and time. + 请输入有效的日期与时间。 + + + Please enter a valid date. + 请输入有效的日期。 + + + Please select a valid file. + 请选择有效的文件。 + + + The hidden field is invalid. + 隐藏字段无效。 + + + Please enter an integer. + 请输入整数。 + + + Please select a valid language. + 请选择有效的语言。 + + + Please select a valid locale. + 请选择有效的语言环境。 + + + Please enter a valid money amount. + 请输入正确的金额。 + + + Please enter a number. + 请输入数字。 + + + The password is invalid. + 密码无效。 + + + Please enter a percentage value. + 请输入百分比值。 + + + The values do not match. + 数值不匹配。 + + + Please enter a valid time. + 请输入有效的时间。 + + + Please select a valid timezone. + 请选择有效的时区。 + + + Please enter a valid URL. + 请输入有效的网址。 + + + Please enter a valid search term. + 请输入有效的搜索词。 + + + Please provide a valid phone number. + 请提供有效的手机号码。 + + + The checkbox has an invalid value. + 无效的选框值。 + + + Please enter a valid email address. + 请输入有效的电子邮件地址。 + + + Please select a valid option. + 请选择有效的选项。 + + + Please select a valid range. + 请选择有效的范围。 + + + Please enter a valid week. + 请输入有效的星期。 + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.zh_CN.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.zh_CN.xlf index 2d6affecec2cc..f8a77f8d1e42d 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.zh_CN.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.zh_CN.xlf @@ -66,6 +66,14 @@ Account is locked. 帐号已被锁定。 + + Too many failed login attempts, please try again later. + 登入失败的次数过多,请稍后再试。 + + + Invalid or expired login link. + 失效或过期的登入链接。 + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf index 3c2f25c0f7bbc..43ac9143bb963 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf @@ -334,6 +334,58 @@ This value should be valid JSON. 该值应该是有效的JSON。 + + This collection should contain only unique elements. + 该集合应仅包含独一无二的元素。 + + + This value should be positive. + 数值应为正数。 + + + This value should be either positive or zero. + 数值应是正数,或为零。 + + + This value should be negative. + 数值应为负数。 + + + This value should be either negative or zero. + 数值应是负数,或为零。 + + + This value is not a valid timezone. + 无效时区。 + + + This password has been leaked in a data breach, it must not be used. Please use another password. + 此密码已被泄露,切勿使用。请更换密码。 + + + This value should be between {{ min }} and {{ max }}. + 该数值应在 {{ min }} 和 {{ max }} 之间。 + + + This value is not a valid hostname. + 该数值不是有效的主机名称。 + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + 该集合内的元素数量得是 {{ compared_value }} 的倍数。 + + + This value should satisfy at least one of the following constraints: + 该数值需符合以下其中一个约束: + + + Each element of this collection should satisfy its own set of constraints. + 该集合内的每个元素需符合元素本身规定的约束。 + + + This value is not a valid International Securities Identification Number (ISIN). + 该数值不是有效的国际证券识别码 (ISIN)。 + From 3e741fda0ae143c5849699a7f0dccbadb2c32e5c Mon Sep 17 00:00:00 2001 From: fd6130 Date: Wed, 28 Oct 2020 01:55:27 +0800 Subject: [PATCH 144/146] Missing translations for Chinese (zh_TW) #38733 --- .../translations/validators.zh_TW.xlf | 139 ++++++++++++++++++ .../Resources/translations/security.zh_TW.xlf | 79 ++++++++++ .../translations/validators.zh_TW.xlf | 26 +++- 3 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Form/Resources/translations/validators.zh_TW.xlf create mode 100644 src/Symfony/Component/Security/Core/Resources/translations/security.zh_TW.xlf diff --git a/src/Symfony/Component/Form/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Form/Resources/translations/validators.zh_TW.xlf new file mode 100644 index 0000000000000..858b9db42ea5f --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.zh_TW.xlf @@ -0,0 +1,139 @@ + + + + + + This form should not contain extra fields. + 該表單中不可有額外字段。 + + + The uploaded file was too large. Please try to upload a smaller file. + 上傳文件太大, 請重新嘗試上傳一個較小的文件。 + + + The CSRF token is invalid. Please try to resubmit the form. + CSRF 驗證符無效, 請重新提交。 + + + This value is not a valid HTML5 color. + 該數值不是個有效的 HTML5 顏色。 + + + Please enter a valid birthdate. + 請輸入有效的生日日期。 + + + The selected choice is invalid. + 所選的選項無效。 + + + The collection is invalid. + 集合無效。 + + + Please select a valid color. + 請選擇有效的顏色。 + + + Please select a valid country. + 請選擇有效的國家。 + + + Please select a valid currency. + 請選擇有效的貨幣。 + + + Please choose a valid date interval. + 請選擇有效的日期間隔。 + + + Please enter a valid date and time. + 請輸入有效的日期與時間。 + + + Please enter a valid date. + 請輸入有效的日期。 + + + Please select a valid file. + 請選擇有效的文件。 + + + The hidden field is invalid. + 隱藏字段無效。 + + + Please enter an integer. + 請輸入整數。 + + + Please select a valid language. + 請選擇有效的語言。 + + + Please select a valid locale. + 請選擇有效的語言環境。 + + + Please enter a valid money amount. + 請輸入正確的金額。 + + + Please enter a number. + 請輸入數字。 + + + The password is invalid. + 密碼無效。 + + + Please enter a percentage value. + 請輸入百分比值。 + + + The values do not match. + 數值不匹配。 + + + Please enter a valid time. + 請輸入有效的時間。 + + + Please select a valid timezone. + 請選擇有效的時區。 + + + Please enter a valid URL. + 請輸入有效的網址。 + + + Please enter a valid search term. + 請輸入有效的搜索詞。 + + + Please provide a valid phone number. + 請提供有效的手機號碼。 + + + The checkbox has an invalid value. + 無效的選框值。 + + + Please enter a valid email address. + 請輸入有效的電子郵件地址。 + + + Please select a valid option. + 請選擇有效的選項。 + + + Please select a valid range. + 請選擇有效的範圍。 + + + Please enter a valid week. + 請輸入有效的星期。 + + + + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.zh_TW.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.zh_TW.xlf new file mode 100644 index 0000000000000..7085206440528 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.zh_TW.xlf @@ -0,0 +1,79 @@ + + + + + + An authentication exception occurred. + 身份驗證發生異常。 + + + Authentication credentials could not be found. + 沒有找到身份驗證的憑證。 + + + Authentication request could not be processed due to a system problem. + 由於系統故障,身份驗證的請求無法被處理。 + + + Invalid credentials. + 無效的憑證。 + + + Cookie has already been used by someone else. + Cookie 已經被其他人使用。 + + + Not privileged to request the resource. + 沒有權限請求此資源。 + + + Invalid CSRF token. + 無效的 CSRF token 。 + + + Digest nonce has expired. + 摘要隨機串(digest nonce)已過期。 + + + No authentication provider found to support the authentication token. + 沒有找到支持此 token 的身份驗證服務提供方。 + + + No session available, it either timed out or cookies are not enabled. + Session 不可用。回話超時或沒有啓用 cookies 。 + + + No token could be found. + 找不到 token 。 + + + Username could not be found. + 找不到用戶名。 + + + Account has expired. + 賬號已逾期。 + + + Credentials have expired. + 憑證已逾期。 + + + Account is disabled. + 賬號已被禁用。 + + + Account is locked. + 賬號已被鎖定。 + + + Too many failed login attempts, please try again later. + 登入失敗的次數過多,請稍後再試。 + + + Invalid or expired login link. + 失效或過期的登入鏈接。 + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index 7cef875f5812e..aa476ea25de17 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -344,7 +344,7 @@ This value should be either positive or zero. - 數值應或未正數,或為零。 + 數值應是正數,或為零。 This value should be negative. @@ -352,7 +352,7 @@ This value should be either negative or zero. - 數值應或未負數,或為零。 + 數值應是負數,或為零。 This value is not a valid timezone. @@ -360,12 +360,32 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - 依據您的密碼,發生數據泄露,請勿使用改密碼。請更換密碼。 + 此密碼已被泄露,切勿使用。請更換密碼。 This value should be between {{ min }} and {{ max }}. 該數值應在 {{ min }} 和 {{ max }} 之間。 + + This value is not a valid hostname. + 該數值不是有效的主機名稱。 + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + 該集合內的元素數量得是 {{ compared_value }} 的倍數。 + + + This value should satisfy at least one of the following constraints: + 該數值需符合以下其中一個約束: + + + Each element of this collection should satisfy its own set of constraints. + 該集合內的每個元素需符合元素本身規定的約束。 + + + This value is not a valid International Securities Identification Number (ISIN). + 該數值不是有效的國際證券識別碼 (ISIN)。 + From 0ef1cc3cf649b0bca2a2c685af86f8ba41e4a0e3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 28 Oct 2020 07:08:27 +0100 Subject: [PATCH 145/146] Update CHANGELOG for 5.2.0-BETA3 --- CHANGELOG-5.2.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md index 67141ddfd516d..0b7a3974cf757 100644 --- a/CHANGELOG-5.2.md +++ b/CHANGELOG-5.2.md @@ -7,6 +7,59 @@ in 5.2 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.2.0...v5.2.1 +* 5.2.0-BETA3 (2020-10-28) + + * bug #38845 [Console] Register signal handling only for commands implemeting SignalableCommandInterface (lyrixx) + * bug #38751 [Security] Move AbstractListener abstract methods to the new FirewallListenerInterface (chalasr) + * bug #38713 [DI] Fix Preloader exception when preloading a class with an unknown parent/interface (rgeraads) + * feature #38664 [RateLimiter] Moved classes implementing LimiterInterface to a new namespace (Nyholm) + * bug #38647 [HttpClient] relax auth bearer format requirements (xabbuh) + * bug #38675 [RateLimiter] Rename RateLimiter to RateLimiterFactory (Nyholm) + * bug #38699 [DependencyInjection] Preload classes with union types correctly (derrabus) + * feature #38688 [HttpClient] Add a Stopwatch on TraceableHttpClient (jderusse) + * bug #38669 [Serializer] fix decoding float XML attributes starting with 0 (Marcin Kruk) + * bug #38680 [PhpUnitBridge] Support new expect methods in test case polyfill (alcaeus) + * bug #38681 [PHPUnitBridge] Support PHPUnit 8 and PHPUnit 9 in constraint compatibility trait (alcaeus) + * bug #38686 [TwigBridge] Remove "transchoice" from the code base (nicolas-grekas) + * bug #38661 [RateLimiter] Fix delete method of the cache storage (GregOriol, Nyholm) + * bug #38678 [String] fix before/after[Last]() returning the empty string instead of the original one on non-match (nicolas-grekas) + * bug #38682 [HttpClient] never trace content of event-stream responses (nicolas-grekas) + * bug #38679 [PhpUnitBridge] Add missing exporter function for PHPUnit 7 (alcaeus) + * bug #38674 [RateLimiter] Make sure we actually can use sliding_window and no_limit (Nyholm) + * bug #38670 [RateLimiter] Be more type safe when fetching from cache (Nyholm) + * bug #38665 [RateLimiter] Allow configuration value "no_limit" (Nyholm) + * bug #38659 [String] fix slicing in UnicodeString (nicolas-grekas) + * bug #38633 [HttpClient] Fix decorating progress info in AsyncResponse (jderusse) + * feature #38543 [HttpKernel] add `kernel.runtime_environment` = `env(default:kernel.environment:APP_RUNTIME_ENV)` parameter (nicolas-grekas) + * bug #38595 [TwigBridge] do not translate null placeholders or titles (xabbuh) + * feature #38653 [DoctrineBridge] Enabled to use the UniqueEntity constraint as an attribute (derrabus) + * bug #38635 [Cache] Use correct expiry in ChainAdapter (Nyholm) + * bug #38652 [Filesystem] Check if failed unlink was caused by permission denied (Nyholm) + * bug #38645 [PropertyAccess] forward the caught exception (xabbuh) + * bug #38644 [FrameworkBundle] remove transport factory service when class does not exist (xabbuh) + * feature #38426 [HttpClient] Parameterize list of retryable methods (jderusse) + * feature #38608 [RateLimiter] rename Limit to RateLimit and add RateLimit::getLimit() (kbond) + * bug #38617 [Form] Add missing invalid_message translations (wouterj) + * bug #38612 [Messenger/Amqp] Allow setting option "login" in DSN (W0rma) + * bug #38618 [Messenger][Doctrine] Avoid early db access for pgsql detection (chalasr) + * bug #38623 [HttpFoundation][RateLimiter] fix RequestRateLimiterInterface::reset() (kbond) + * bug #38604 [DoctrineBridge] indexBy does not refer to attributes, but to column names (xabbuh) + * bug #38605 [DoctrinBridge] make Uid types stricter (nicolas-grekas) + * bug #38606 [WebProfilerBundle] Hide debug toolbar in print view (jt2k) + * bug #38602 [Console] Fix signal management (chalasr) + * bug #38600 [DoctrineBridge] Convert values to Rfc4122 before inserting them into the database (Kai) + * feature #38562 [RateLimiter] Added reserve() to LimiterInterface and rename Limiter to RateLimiter (wouterj) + * feature #38593 [Lock][Semaphore] Add Factory::createFromKey and deprecate lock.store services (jderusse) + * feature #38587 [HttpClient] added `extra.trace_content` option to `TraceableHttpClient` to prevent it from keeping the content in memory (nicolas-grekas) + * bug #38580 [FrameworkBundle] fix config declaration of http_cache option (nicolas-grekas) + * bug #38589 [Console] Don't register signal handlers if pcntl is disabled (chalasr) + * bug #38581 [Semaphore] Reset Key lifetime time before we acquire it (jderusse) + * bug #38582 [DI] Fix Reflection file name with eval()\'d code (maxime-aknin) + * feature #38565 [RateLimiter] Adding SlidingWindow algorithm (Nyholm) + * feature #38576 Deeprecate lock service (jderusse) + * bug #38578 Add missing use statement (jderusse) + * bug #38516 [HttpFoundation] Fix Range Requests (BattleRattle) + * 5.2.0-BETA2 (2020-10-14) * feature #38552 [Security][Notifier] Added integration of Login Link with the Notifier component (wouterj) From d034e0455d11f85bbe05c579be58cdb351025f02 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 28 Oct 2020 07:08:40 +0100 Subject: [PATCH 146/146] Update VERSION for 5.2.0-BETA3 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c5a6be5344429..5d42e45e6e08d 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,12 +74,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '5.2.0-DEV'; + const VERSION = '5.2.0-BETA3'; const VERSION_ID = 50200; const MAJOR_VERSION = 5; const MINOR_VERSION = 2; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = 'BETA3'; const END_OF_MAINTENANCE = '07/2021'; const END_OF_LIFE = '07/2021';