From e96add478738a251928b9d53fa0d3838d421299f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Sep 2019 19:18:47 +0200 Subject: [PATCH 01/26] [Crawler] document $default as string|null --- src/Symfony/Component/DomCrawler/Crawler.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 2fa18191ab..b783c19a8e 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -554,17 +554,17 @@ class Crawler implements \Countable, \IteratorAggregate /** * Returns the node value of the first node of the list. * - * @param mixed $default When provided and the current node is empty, this value is returned and no exception is thrown + * @param string|null $default When not null: the value to return when the current node is empty * * @return string The node value * * @throws \InvalidArgumentException When current node is empty */ - public function text(/* $default = null */) + public function text(/* string $default = null */) { if (!$this->nodes) { - if (0 < \func_num_args()) { - return func_get_arg(0); + if (0 < \func_num_args() && null !== func_get_arg(0)) { + return (string) func_get_arg(0); } throw new \InvalidArgumentException('The current node list is empty.'); @@ -576,17 +576,17 @@ class Crawler implements \Countable, \IteratorAggregate /** * Returns the first node of the list as HTML. * - * @param mixed $default When provided and the current node is empty, this value is returned and no exception is thrown + * @param string|null $default When not null: the value to return when the current node is empty * * @return string The node html * * @throws \InvalidArgumentException When current node is empty */ - public function html(/* $default = null */) + public function html(/* string $default = null */) { if (!$this->nodes) { - if (0 < \func_num_args()) { - return func_get_arg(0); + if (0 < \func_num_args() && null !== func_get_arg(0)) { + return (string) func_get_arg(0); } throw new \InvalidArgumentException('The current node list is empty.'); From dfa23034c3885f0d6e63eb43648027f262b9a0fe Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 7 Oct 2019 15:00:46 +0200 Subject: [PATCH 02/26] [Form][DateTimeImmutableToDateTimeTransformer] Preserve microseconds and use \DateTime::createFromImmutable() when available --- ...DateTimeImmutableToDateTimeTransformer.php | 6 +++- ...TimeImmutableToDateTimeTransformerTest.php | 34 ++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php index b0737393e4..167ea57fae 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php @@ -40,7 +40,11 @@ final class DateTimeImmutableToDateTimeTransformer implements DataTransformerInt throw new TransformationFailedException('Expected a \DateTimeImmutable.'); } - return \DateTime::createFromFormat(\DateTime::RFC3339, $value->format(\DateTime::RFC3339)); + if (\PHP_VERSION_ID >= 70300) { + return \DateTime::createFromImmutable($value); + } + + return \DateTime::createFromFormat('U.u', $value->format('U.u'))->setTimezone($value->getTimezone()); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php index 9313e4f178..c8b6549778 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php @@ -16,16 +16,33 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDat class DateTimeImmutableToDateTimeTransformerTest extends TestCase { - public function testTransform() + /** + * @dataProvider provider + */ + public function testTransform(\DateTime $expectedOutput, \DateTimeImmutable $input) { $transformer = new DateTimeImmutableToDateTimeTransformer(); - $input = new \DateTimeImmutable('2010-02-03 04:05:06 UTC'); - $expectedOutput = new \DateTime('2010-02-03 04:05:06 UTC'); $actualOutput = $transformer->transform($input); - $this->assertInstanceOf(\DateTime::class, $actualOutput); $this->assertEquals($expectedOutput, $actualOutput); + $this->assertEquals($expectedOutput->getTimezone(), $actualOutput->getTimezone()); + } + + public function provider() + { + return [ + [ + new \DateTime('2010-02-03 04:05:06 UTC'), + new \DateTimeImmutable('2010-02-03 04:05:06 UTC'), + ], + [ + (new \DateTime('2019-10-07 +11:00')) + ->setTime(14, 27, 11, 10042), + (new \DateTimeImmutable('2019-10-07 +11:00')) + ->setTime(14, 27, 11, 10042), + ], + ]; } public function testTransformEmpty() @@ -43,16 +60,17 @@ class DateTimeImmutableToDateTimeTransformerTest extends TestCase $transformer->transform(new \DateTime()); } - public function testReverseTransform() + /** + * @dataProvider provider + */ + public function testReverseTransform(\DateTime $input, \DateTimeImmutable $expectedOutput) { $transformer = new DateTimeImmutableToDateTimeTransformer(); - $input = new \DateTime('2010-02-03 04:05:06 UTC'); - $expectedOutput = new \DateTimeImmutable('2010-02-03 04:05:06 UTC'); $actualOutput = $transformer->reverseTransform($input); - $this->assertInstanceOf(\DateTimeImmutable::class, $actualOutput); $this->assertEquals($expectedOutput, $actualOutput); + $this->assertEquals($expectedOutput->getTimezone(), $actualOutput->getTimezone()); } public function testReverseTransformEmpty() From 6f32584c7663a1303580ca06a81dcc5a478fff59 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 4 Oct 2019 16:41:42 +0200 Subject: [PATCH 03/26] [EventDispatcher] Allow to omit the event name when registering listeners. --- .../Component/EventDispatcher/CHANGELOG.md | 1 + .../RegisterListenersPass.php | 28 +++- .../RegisterListenersPassTest.php | 151 ++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/Symfony/Component/EventDispatcher/CHANGELOG.md index d607b808a0..2e5afbc6f5 100644 --- a/src/Symfony/Component/EventDispatcher/CHANGELOG.md +++ b/src/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. +* Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. 4.3.0 ----- diff --git a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php index ffded127ac..9c88809de0 100644 --- a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php +++ b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php @@ -16,8 +16,10 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\EventDispatcher\Event as LegacyEvent; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Compiler pass to register tagged services for an event dispatcher. @@ -67,8 +69,14 @@ class RegisterListenersPass implements CompilerPassInterface $priority = isset($event['priority']) ? $event['priority'] : 0; if (!isset($event['event'])) { - throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + if ($container->getDefinition($id)->hasTag($this->subscriberTag)) { + continue; + } + + $event['method'] = $event['method'] ?? '__invoke'; + $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']); } + $event['event'] = $aliases[$event['event']] ?? $event['event']; if (!isset($event['method'])) { @@ -122,6 +130,24 @@ class RegisterListenersPass implements CompilerPassInterface ExtractingEventDispatcher::$aliases = []; } } + + private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string + { + if ( + null === ($class = $container->getDefinition($id)->getClass()) + || !($r = $container->getReflectionClass($class, false)) + || !$r->hasMethod($method) + || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() + || !($type = $m->getParameters()[0]->getType()) + || $type->isBuiltin() + || Event::class === ($name = $type->getName()) + || LegacyEvent::class === $name + ) { + throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + } + + return $name; + } } /** diff --git a/src/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/src/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php index c21d6ca1cf..5252664a9f 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\DependencyInjection\AddEventAliasesPass; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; @@ -244,6 +245,116 @@ class RegisterListenersPassTest extends TestCase ]; $this->assertEquals($expectedCalls, $definition->getMethodCalls()); } + + public function testOmitEventNameOnTypedListener(): void + { + $container = new ContainerBuilder(); + $container->setParameter('event_dispatcher.event_aliases', [AliasedEvent::class => 'aliased_event']); + $container->register('foo', TypedListener::class)->addTag('kernel.event_listener', ['method' => 'onEvent']); + $container->register('bar', TypedListener::class)->addTag('kernel.event_listener'); + $container->register('event_dispatcher'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + + $definition = $container->getDefinition('event_dispatcher'); + $expectedCalls = [ + [ + 'addListener', + [ + CustomEvent::class, + [new ServiceClosureArgument(new Reference('foo')), 'onEvent'], + 0, + ], + ], + [ + 'addListener', + [ + 'aliased_event', + [new ServiceClosureArgument(new Reference('bar')), '__invoke'], + 0, + ], + ], + ]; + $this->assertEquals($expectedCalls, $definition->getMethodCalls()); + } + + public function testOmitEventNameOnUntypedListener(): void + { + $container = new ContainerBuilder(); + $container->register('foo', InvokableListenerService::class)->addTag('kernel.event_listener', ['method' => 'onEvent']); + $container->register('event_dispatcher'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Service "foo" must define the "event" attribute on "kernel.event_listener" tags.'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + public function testOmitEventNameAndMethodOnUntypedListener(): void + { + $container = new ContainerBuilder(); + $container->register('foo', InvokableListenerService::class)->addTag('kernel.event_listener'); + $container->register('event_dispatcher'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Service "foo" must define the "event" attribute on "kernel.event_listener" tags.'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @requires PHP 7.2 + */ + public function testOmitEventNameAndMethodOnGenericListener(): void + { + $container = new ContainerBuilder(); + $container->register('foo', GenericListener::class)->addTag('kernel.event_listener'); + $container->register('event_dispatcher'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Service "foo" must define the "event" attribute on "kernel.event_listener" tags.'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + public function testOmitEventNameOnSubscriber(): void + { + $container = new ContainerBuilder(); + $container->register('subscriber', IncompleteSubscriber::class) + ->addTag('kernel.event_subscriber') + ->addTag('kernel.event_listener') + ->addTag('kernel.event_listener', ['event' => 'bar', 'method' => 'onBar']) + ; + $container->register('event_dispatcher'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + + $definition = $container->getDefinition('event_dispatcher'); + $expectedCalls = [ + [ + 'addListener', + [ + 'bar', + [new ServiceClosureArgument(new Reference('subscriber')), 'onBar'], + 0, + ], + ], + [ + 'addListener', + [ + 'foo', + [new ServiceClosureArgument(new Reference('subscriber')), 'onFoo'], + 0, + ], + ], + ]; + $this->assertEquals($expectedCalls, $definition->getMethodCalls()); + } } class SubscriberService implements EventSubscriberInterface @@ -285,3 +396,43 @@ final class AliasedEvent final class CustomEvent { } + +final class TypedListener +{ + public function __invoke(AliasedEvent $event): void + { + } + + public function onEvent(CustomEvent $event): void + { + } +} + +final class GenericListener +{ + public function __invoke(object $event): void + { + } +} + +final class IncompleteSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents(): array + { + return [ + 'foo' => 'onFoo', + ]; + } + + public function onFoo(): void + { + } + + public function onBar(): void + { + } + + public function __invoke(CustomEvent $event): void + { + } +} From 02414027e1ef3b5bf0537217c29fdb6482944f92 Mon Sep 17 00:00:00 2001 From: Ben Davies Date: Mon, 1 Jul 2019 15:13:09 +0100 Subject: [PATCH 04/26] [Messenger] DoctrineTransport: ensure auto setup is only done once --- .../Doctrine/DoctrineIntegrationTest.php | 40 +++++++++---------- .../Transport/Doctrine/Connection.php | 27 +++++++------ 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index 6770733964..fa05a43b0b 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -21,29 +21,27 @@ use Symfony\Component\Messenger\Transport\Doctrine\Connection; */ class DoctrineIntegrationTest extends TestCase { + /** @var \Doctrine\DBAL\Connection */ private $driverConnection; + /** @var Connection */ private $connection; + /** @var string */ + private $sqliteFile; - /** - * @after - */ - public function cleanup() + protected function setUp(): void { - @unlink(sys_get_temp_dir().'/symfony.messenger.sqlite'); - } - - /** - * @before - */ - public function createConnection() - { - $dsn = getenv('MESSENGER_DOCTRINE_DSN') ?: 'sqlite:///'.sys_get_temp_dir().'/symfony.messenger.sqlite'; + $this->sqliteFile = sys_get_temp_dir().'/symfony.messenger.sqlite'; + $dsn = getenv('MESSENGER_DOCTRINE_DSN') ?: 'sqlite:///'.$this->sqliteFile; $this->driverConnection = DriverManager::getConnection(['url' => $dsn]); $this->connection = new Connection([], $this->driverConnection); - // call send to auto-setup the table - $this->connection->setup(); - // ensure the table is clean for tests - $this->driverConnection->exec('DELETE FROM messenger_messages'); + } + + protected function tearDown(): void + { + $this->driverConnection->close(); + if (file_exists($this->sqliteFile)) { + unlink($this->sqliteFile); + } } public function testConnectionSendAndGet() @@ -75,6 +73,7 @@ class DoctrineIntegrationTest extends TestCase public function testItRetrieveTheFirstAvailableMessage() { + $this->connection->setup(); // insert messages // one currently handled $this->driverConnection->insert('messenger_messages', [ @@ -108,6 +107,7 @@ class DoctrineIntegrationTest extends TestCase public function testItCountMessages() { + $this->connection->setup(); // insert messages // one currently handled $this->driverConnection->insert('messenger_messages', [ @@ -148,6 +148,7 @@ class DoctrineIntegrationTest extends TestCase public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout() { + $this->connection->setup(); $twoHoursAgo = new \DateTime('now'); $twoHoursAgo->modify('-2 hours'); $this->driverConnection->insert('messenger_messages', [ @@ -173,10 +174,7 @@ class DoctrineIntegrationTest extends TestCase public function testTheTransportIsSetupOnGet() { - // If the table does not exist and we call the get (i.e run messenger:consume) the table must be setup - // so first delete the tables - $this->driverConnection->exec('DROP TABLE messenger_messages'); - + $this->assertFalse($this->driverConnection->getSchemaManager()->tablesExist('messenger_messages')); $this->assertNull($this->connection->get()); $this->connection->send('the body', ['my' => 'header']); diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 41cf70bbf0..2c8bcd35cc 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -52,12 +52,14 @@ class Connection private $configuration = []; private $driverConnection; private $schemaSynchronizer; + private $autoSetup; public function __construct(array $configuration, DBALConnection $driverConnection, SchemaSynchronizer $schemaSynchronizer = null) { $this->configuration = array_replace_recursive(self::DEFAULT_OPTIONS, $configuration); $this->driverConnection = $driverConnection; $this->schemaSynchronizer = $schemaSynchronizer ?? new SingleDatabaseSynchronizer($this->driverConnection); + $this->autoSetup = $this->configuration['auto_setup']; } public function getConfiguration(): array @@ -131,9 +133,7 @@ class Connection public function get(): ?array { - if ($this->configuration['auto_setup']) { - $this->setup(); - } + get: $this->driverConnection->beginTransaction(); try { $query = $this->createAvailableMessagesQueryBuilder() @@ -170,6 +170,11 @@ class Connection } catch (\Throwable $e) { $this->driverConnection->rollBack(); + if ($this->autoSetup && $e instanceof TableNotFoundException) { + $this->setup(); + goto get; + } + throw $e; } } @@ -213,6 +218,8 @@ class Connection } else { $this->driverConnection->getConfiguration()->setFilterSchemaAssetsExpression($assetFilter); } + + $this->autoSetup = false; } public function getMessageCount(): int @@ -226,10 +233,6 @@ class Connection public function findAll(int $limit = null): array { - if ($this->configuration['auto_setup']) { - $this->setup(); - } - $queryBuilder = $this->createAvailableMessagesQueryBuilder(); if (null !== $limit) { $queryBuilder->setMaxResults($limit); @@ -244,10 +247,6 @@ class Connection public function find($id): ?array { - if ($this->configuration['auto_setup']) { - $this->setup(); - } - $queryBuilder = $this->createQueryBuilder() ->where('m.id = ?'); @@ -288,8 +287,12 @@ class Connection $stmt = $this->driverConnection->prepare($sql); $stmt->execute($parameters); } catch (TableNotFoundException $e) { + if ($this->driverConnection->isTransactionActive()) { + throw $e; + } + // create table - if (!$this->driverConnection->isTransactionActive() && $this->configuration['auto_setup']) { + if ($this->autoSetup) { $this->setup(); } // statement not prepared ? SQLite throw on exception on prepare if the table does not exist From ed01f3c51167f8063b000112162e5ab991123158 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 16:41:35 +0200 Subject: [PATCH 05/26] updated CHANGELOG for 3.4.32 --- CHANGELOG-3.4.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index f92c85dd9c..015ca124b1 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,46 @@ in 3.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.4.0...v3.4.1 +* 3.4.32 (2019-10-07) + + * bug #33834 [Validator] Fix ValidValidator group cascading usage (fancyweb) + * bug #33841 [VarDumper] fix dumping uninitialized SplFileInfo (nicolas-grekas) + * bug #33799 [Security]: Don't let falsy usernames slip through impersonation (j4nr6n) + * bug #33814 [HttpFoundation] Check if data passed to SessionBagProxy::initialize is an array (mynameisbogdan) + * bug #33805 [FrameworkBundle] Fix wrong returned status code in ConfigDebugCommand (jschaedl) + * bug #33781 [AnnotationCacheWarmer] add RedirectController to annotation cache (jenschude) + * bug #33777 Fix the :only-of-type pseudo class selector (jakzal) + * bug #32051 [Serializer] Add CsvEncoder tests for PHP 7.4 (ro0NL) + * feature #33776 Copy phpunit.xsd to a predictable path (julienfalque) + * bug #33759 [Security/Http] fix parsing X509 emailAddress (nicolas-grekas) + * bug #33733 [Serializer] fix denormalization of string-arrays with only one element (mkrauser) + * bug #33754 [Cache] fix known tag versions ttl check (SwenVanZanten) + * bug #33646 [HttpFoundation] allow additinal characters in not raw cookies (marie) + * bug #33748 [Console] Do not include hidden commands in suggested alternatives (m-vo) + * bug #33625 [DependencyInjection] Fix wrong exception when service is synthetic (k0d3r1s) + * bug #32522 [Validator] Accept underscores in the URL validator, as the URL will load (battye) + * bug #32437 Fix toolbar load when GET params are present in "_wdt" route (Molkobain) + * bug #32925 [Translation] Collect original locale in case of fallback translation (digilist) + * bug #31198 [FrameworkBundle] Fix framework bundle lock configuration not working as expected (HypeMC) + * bug #33719 [Cache] dont override native Memcached options (nicolas-grekas) + * bug #33675 [PhpUnit] Fix usleep mock return value (fabpot) + * bug #33618 fix tests depending on other components' tests (xabbuh) + * bug #33626 [PropertyInfo] ensure compatibility with type resolver 0.5 (xabbuh) + * bug #33620 [Twig] Fix Twig config extra keys (fabpot) + * bug #33571 [Inflector] add support 'see' to 'ee' for singularize 'fees' to 'fee' (maxhelias) + * bug #32763 [Console] Get dimensions from stty on windows if possible (rtek) + * bug #33518 [Yaml] don't dump a scalar tag value on its own line (xabbuh) + * bug #32818 [HttpKernel] Fix getFileLinkFormat() to avoid returning the wrong URL in Profiler (Arman-Hosseini) + * bug #33487 [HttpKernel] Fix Apache mod_expires Session Cache-Control issue (pbowyer) + * bug #33439 [Validator] Sync string to date behavior and throw a better exception (fancyweb) + * bug #32903 [PHPUnit Bridge] Avoid registering listener twice (alexpott) + * bug #33402 [Finder] Prevent unintentional file locks in Windows (jspringe) + * bug #33396 Fix #33395 PHP 5.3 compatibility (kylekatarnls) + * bug #33385 [Console] allow Command::getName() to return null (nicolas-grekas) + * bug #33353 Return null as Expire header if it was set to null (danrot) + * bug #33382 [ProxyManager] remove ProxiedMethodReturnExpression polyfill (nicolas-grekas) + * bug #33377 [Yaml] fix dumping not inlined scalar tag values (xabbuh) + * 3.4.31 (2019-08-26) * bug #33335 [DependencyInjection] Fixed the `getServiceIds` implementation to always return aliases (pdommelen) From fd683f05ea6ba923a760efb29d60ec65ef2dd812 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 16:41:46 +0200 Subject: [PATCH 06/26] update CONTRIBUTORS for 3.4.32 --- CONTRIBUTORS.md | 110 ++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 963f9e9602..2cf905be32 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -6,36 +6,36 @@ Symfony is the result of the work of many people who made the code better - Fabien Potencier (fabpot) - Nicolas Grekas (nicolas-grekas) - - Bernhard Schussek (bschussek) - Christian Flothmann (xabbuh) + - Bernhard Schussek (bschussek) - Tobias Schultze (tobion) - Christophe Coevoet (stof) - Robin Chalas (chalas_r) - Jordi Boggiano (seldaek) - - Victor Berchet (victor) - Kévin Dunglas (dunglas) + - Victor Berchet (victor) - Maxime Steinhausser (ogizanagi) - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) - - Jakub Zalas (jakubzalas) - Roland Franssen (ro0) + - Jakub Zalas (jakubzalas) - Johannes S (johannes) - - Kris Wallsmith (kriswallsmith) - Grégoire Pineau (lyrixx) + - Kris Wallsmith (kriswallsmith) - Hugo Hamon (hhamon) + - Yonel Ceruto (yonelceruto) - Abdellatif Ait boudad (aitboudad) - Samuel ROZE (sroze) - - Yonel Ceruto (yonelceruto) - Romain Neutron (romain) - Pascal Borreli (pborreli) - Wouter De Jong (wouterj) - Joseph Bielawski (stloyd) - Karma Dordrak (drak) - Lukas Kahwe Smith (lsmith) + - Alexander M. Turek (derrabus) - Martin Hasoň (hason) - Hamza Amrouche (simperfit) - Jeremy Mikola (jmikola) - - Alexander M. Turek (derrabus) - Jean-François Simon (jfsimon) - Jules Pietri (heah) - Benjamin Eberlei (beberlei) @@ -44,21 +44,21 @@ Symfony is the result of the work of many people who made the code better - Eriksen Costa (eriksencosta) - Guilhem Niot (energetick) - Sarah Khalil (saro0h) + - Thomas Calvet (fancyweb) - Tobias Nyholm (tobias) - Jonathan Wage (jwage) - Lynn van der Berg (kjarli) - Diego Saint Esteben (dosten) - - Thomas Calvet (fancyweb) - Alexandre Salomé (alexandresalome) - William Durand (couac) - ornicar + - Pierre du Plessis (pierredup) - Dany Maillard (maidmaid) - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - - Pierre du Plessis (pierredup) - - Matthias Pigulla (mpdude) - Konstantin Myakshin (koc) + - Matthias Pigulla (mpdude) - Bulat Shakirzyanov (avalanche123) - Grégoire Paris (greg0ire) - Saša Stamenković (umpirsky) @@ -69,13 +69,13 @@ Symfony is the result of the work of many people who made the code better - Miha Vrhovnik - Diego Saint Esteben (dii3g0) - Gábor Egyed (1ed) - - Konstantin Kudryashov (everzet) - Titouan Galopin (tgalopin) + - Konstantin Kudryashov (everzet) + - David Maicher (dmaicher) - Bilal Amarni (bamarni) - Mathieu Piot (mpiot) - - David Maicher (dmaicher) - - Florin Patan (florinpatan) - Gabriel Ostrolucký (gadelat) + - Florin Patan (florinpatan) - Vladimir Reznichenko (kalessil) - Jáchym Toušek (enumag) - Michel Weimerskirch (mweimerskirch) @@ -83,6 +83,7 @@ Symfony is the result of the work of many people who made the code better - Issei Murasawa (issei_m) - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) + - Jan Schädlich (jschaedl) - Christian Raue - Arnout Boks (aboks) - Deni @@ -90,7 +91,6 @@ Symfony is the result of the work of many people who made the code better - Dariusz Górecki (canni) - Douglas Greenshields (shieldo) - David Buchmann (dbu) - - Jan Schädlich (jschaedl) - Dariusz Ruminski - Lee McDermott - Brandon Turner @@ -114,30 +114,30 @@ Symfony is the result of the work of many people who made the code better - Baptiste Clavié (talus) - marc.weistroff - Tomáš Votruba (tomas_votruba) + - Jérôme Vasseur (jvasseur) - lenar - Alexander Schwenn (xelaris) - Włodzimierz Gajda (gajdaw) - - Jérôme Vasseur (jvasseur) + - Sebastiaan Stok (sstok) + - Adrien Brault (adrienbrault) - Peter Kokot (maastermedia) - Jacob Dreesen (jdreesen) - Florian Voutzinos (florianv) - - Sebastiaan Stok (sstok) - Colin Frei - Javier Spagnoletti (phansys) - - Adrien Brault (adrienbrault) - Joshua Thijssen - Daniel Wehner (dawehner) - excelwebzone - Gordon Franke (gimler) + - Teoh Han Hui (teohhanhui) - Oskar Stark (oskarstark) + - Alex Pott - Fabien Pennequin (fabienpennequin) - Théo FIDRY (theofidry) - - Teoh Han Hui (teohhanhui) - Eric GELOEN (gelo) - Joel Wurtz (brouznouf) - Lars Strojny (lstrojny) - Tugdual Saunier (tucksaun) - - Alex Pott - Jannik Zschiesche (apfelbox) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) @@ -152,6 +152,7 @@ Symfony is the result of the work of many people who made the code better - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) - Andréia Bohner (andreia) + - Julien Falque (julienfalque) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - SpacePossum @@ -160,7 +161,6 @@ Symfony is the result of the work of many people who made the code better - François-Xavier de Guillebon (de-gui_f) - Oleg Voronkovich - Philipp Wahala (hifi) - - Julien Falque (julienfalque) - Rafael Dohms (rdohms) - jwdeitch - Mikael Pajunen @@ -172,6 +172,7 @@ Symfony is the result of the work of many people who made the code better - Richard Shank (iampersistent) - Thomas Rabaix (rande) - Vincent Touzet (vincenttouzet) + - Gregor Harlan (gharlan) - jeremyFreeAgent (jeremyfreeagent) - Rouven Weßling (realityking) - Alexander Schranz (alexander-schranz) @@ -193,6 +194,7 @@ Symfony is the result of the work of many people who made the code better - James Halsall (jaitsu) - Matthieu Napoli (mnapoli) - Florent Mata (fmata) + - Arman Hosseini - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) @@ -206,11 +208,11 @@ Symfony is the result of the work of many people who made the code better - Mario A. Alvarez Garcia (nomack84) - Dennis Benkert (denderello) - DQNEO - - Gregor Harlan (gharlan) + - mcfedr (mcfedr) - Gary PEGEOT (gary-p) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - - Arman Hosseini + - Andreas Braun - Mathieu Lemoine (lemoinem) - Christian Schmidt - Andreas Hucks (meandmymonkey) @@ -241,7 +243,6 @@ Symfony is the result of the work of many people who made the code better - jeff - John Kary (johnkary) - Andreas Schempp (aschempp) - - Andreas Braun - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - Michele Orselli (orso) @@ -265,7 +266,6 @@ Symfony is the result of the work of many people who made the code better - julien pauli (jpauli) - Lorenz Schori - Sébastien Lavoie (lavoiesl) - - mcfedr (mcfedr) - Dariusz - Michael Babker (mbabker) - Francois Zaninotto @@ -314,12 +314,14 @@ Symfony is the result of the work of many people who made the code better - Jhonny Lidfors (jhonne) - Diego Agulló (aeoris) - jdhoek + - Maxime Helias (maxhelias) - David Prévot - Bob den Otter (bopp) - Thomas Schulz (king2500) - Frank de Jonge (frenkynet) - Nikita Konstantinov - Wodor Wodorski + - dFayet - Thomas Lallement (raziel057) - Colin O'Dell (colinodell) - Giorgio Premi @@ -343,6 +345,7 @@ Symfony is the result of the work of many people who made the code better - Christian Schmidt - Patrick Landolt (scube) - MatTheCat + - David Badura (davidbadura) - Chad Sikorra (chadsikorra) - Chris Smith (cs278) - Florian Klein (docteurklein) @@ -361,6 +364,7 @@ Symfony is the result of the work of many people who made the code better - Jerzy Zawadzki (jzawadzki) - Wouter J - Ismael Ambrosi (iambrosi) + - Ruud Kamphuis (ruudk) - Emmanuel BORGES (eborges78) - Aurelijus Valeiša (aurelijus) - Jan Decavele (jandc) @@ -374,7 +378,6 @@ Symfony is the result of the work of many people who made the code better - Francesc Rosàs (frosas) - Romain Pierre (romain-pierre) - Julien Galenski (ruian) - - Maxime Helias - Bongiraud Dominique - janschoenherr - Emanuele Gaspari (inmarelibero) @@ -382,7 +385,6 @@ Symfony is the result of the work of many people who made the code better - Berny Cantos (xphere81) - Thierry Thuon (lepiaf) - Ricard Clau (ricardclau) - - dFayet - Mark Challoner (markchalloner) - Gennady Telegin (gtelegin) - Erin Millard @@ -410,10 +412,10 @@ Symfony is the result of the work of many people who made the code better - Robbert Klarenbeek (robbertkl) - Eric Masoero (eric-masoero) - JhonnyL - - David Badura (davidbadura) - hossein zolfi (ocean) - Clément Gautier (clementgautier) - Thomas Bisignani (toma) + - Dāvis Zālītis (k0d3r1s) - Sanpi - Eduardo Gulias (egulias) - giulio de donato (liuggio) @@ -436,6 +438,7 @@ Symfony is the result of the work of many people who made the code better - Tamas Szijarto - Michele Locati - Pavel Volokitin (pvolok) + - Valentine Boineau (valentineboineau) - Arthur de Moulins (4rthem) - Matthias Althaus (althaus) - Nicolas Dewez (nicolas_dewez) @@ -447,13 +450,13 @@ Symfony is the result of the work of many people who made the code better - Joe Lencioni - Daniel Tschinder - vladimir.reznichenko - - Ruud Kamphuis (ruudk) - Kai - Lee Rowlands - Krzysztof Piasecki (krzysztek) - Maximilian Reichel (phramz) - Loick Piera (pyrech) - Alain Hippolyte (aloneh) + - Grenier Kévin (mcsky_biig) - Karoly Negyesi (chx) - Ivan Kurnosov - Xavier HAUSHERR @@ -481,9 +484,11 @@ Symfony is the result of the work of many people who made the code better - Jeanmonod David (jeanmonod) - Christopher Davis (chrisguitarguy) - Webnet team (webnet) + - Farhad Safarov - Jan Schumann - Niklas Fiekas - Markus Bachmann (baachi) + - Kévin THERAGE (kevin_therage) - lancergr - Mihai Stancu - Ivan Nikolaev (destillat) @@ -499,6 +504,7 @@ Symfony is the result of the work of many people who made the code better - EdgarPE - Florian Pfitzer (marmelatze) - Asier Illarramendi (doup) + - Sylvain Fabre (sylfabre) - Martijn Cuppens - Vlad Gregurco (vgregurco) - Maciej Malarz (malarzm) @@ -517,6 +523,7 @@ Symfony is the result of the work of many people who made the code better - Tobias Weichart - Gonzalo Vilaseca (gonzalovilaseca) - Marcin Sikoń (marphi) + - Tien Vo (tienvx) - Denis Brumann (dbrumann) - Dominik Zogg (dominik.zogg) - Marek Pietrzak @@ -533,6 +540,7 @@ Symfony is the result of the work of many people who made the code better - Anton Bakai - Martin Auswöger - Rhodri Pugh (rodnaph) + - battye - Sam Fleming (sam_fleming) - Alex Bakhturin - Patrick Reimers (preimers) @@ -606,7 +614,6 @@ Symfony is the result of the work of many people who made the code better - Nate (frickenate) - Timothée Barray (tyx) - jhonnyL - - Grenier Kévin (mcsky_biig) - sasezaki - Dawid Pakuła (zulusx) - Florian Rey (nervo) @@ -621,6 +628,7 @@ Symfony is the result of the work of many people who made the code better - Kevin Saliou (kbsali) - Shawn Iwinski - Gawain Lynch (gawain) + - mmokhi - NothingWeAre - Ryan - Alexander Deruwe (aderuwe) @@ -643,9 +651,11 @@ Symfony is the result of the work of many people who made the code better - Disquedur - Michiel Boeckaert (milio) - Geoffrey Tran (geoff) + - Kyle - Jan Behrens - Mantas Var (mvar) - Chris Tanaskoski + - Terje Bråten - Sebastian Krebs - Piotr Stankowski - Baptiste Leduc (bleduc) @@ -669,6 +679,7 @@ Symfony is the result of the work of many people who made the code better - Kyle Evans (kevans91) - Charles-Henri Bruyand - Max Rath (drak3) + - Oleg Andreyev - Stéphane Escandell (sescandell) - Konstantin S. M. Möllers (ksmmoellers) - James Johnston @@ -676,7 +687,6 @@ Symfony is the result of the work of many people who made the code better - Alexandre Dupuy (satchette) - Malte Blättermann - Desjardins Jérôme (jewome62) - - Kévin THERAGE (kevin_therage) - Simeon Kolev (simeon_kolev9) - Joost van Driel (j92) - Jonas Elfering @@ -693,7 +703,6 @@ Symfony is the result of the work of many people who made the code better - Gunnstein Lye (glye) - Maxime Douailin - Jean Pasdeloup (pasdeloup) - - Sylvain Fabre (sylfabre) - Benjamin Cremer (bcremer) - Javier López (loalf) - Reinier Kip @@ -712,6 +721,7 @@ Symfony is the result of the work of many people who made the code better - DerManoMann - Rostyslav Kinash - Dennis Fridrich (dfridrich) + - Mardari Dorel (dorumd) - Daisuke Ohata - Vincent Simonin - Alex Bogomazov (alebo) @@ -730,6 +740,7 @@ Symfony is the result of the work of many people who made the code better - Miquel Rodríguez Telep (mrtorrent) - Sergey Kolodyazhnyy (skolodyazhnyy) - umpirski + - M. Vondano - Quentin de Longraye (quentinus95) - Chris Heng (gigablah) - Shaun Simmons (simshaun) @@ -750,7 +761,7 @@ Symfony is the result of the work of many people who made the code better - Kristijan Kanalas - Stephan Vock - Benjamin Zikarsky (bzikarsky) - - battye + - Ruben Jacobs (rubenj) - Simon Schick (simonsimcity) - redstar504 - Tristan Roussel @@ -799,6 +810,7 @@ Symfony is the result of the work of many people who made the code better - Indra Gunawan (guind) - Peter Ward - Davide Borsatto (davide.borsatto) + - Markus Fasselt (digilist) - Julien DIDIER (juliendidier) - Dominik Ritter (dritter) - Sebastian Grodzicki (sgrodzicki) @@ -935,7 +947,6 @@ Symfony is the result of the work of many people who made the code better - Benoît Bourgeois - mantulo - Stefan Kruppa - - mmokhi - corphi - JoppeDC - grizlik @@ -1005,10 +1016,8 @@ Symfony is the result of the work of many people who made the code better - Pablo Lozano (arkadis) - Erik Saunier (snickers) - Rootie - - Kyle - Daniel Alejandro Castro Arellano (lexcast) - sensio - - Terje Bråten - Thomas Jarrand - Antoine Bluchet (soyuka) - Sebastien Morel (plopix) @@ -1031,7 +1040,6 @@ Symfony is the result of the work of many people who made the code better - The Whole Life to Learn - Mikkel Paulson - ergiegonzaga - - Farhad Safarov - Liverbool (liverbool) - Sam Malone - Phan Thanh Ha (haphan) @@ -1039,7 +1047,9 @@ Symfony is the result of the work of many people who made the code better - neghmurken - xaav - Mahmoud Mostafa (mahmoud) + - Julien Turby - Ahmed Abdou + - Daniel Iwaniec - Pieter - Michael Tibben - Billie Thompson @@ -1115,6 +1125,7 @@ Symfony is the result of the work of many people who made the code better - Chris Tiearney - Oliver Hoff - Ole Rößner (basster) + - rtek - Faton (notaf) - Tom Houdmont - Per Sandström (per) @@ -1133,6 +1144,7 @@ Symfony is the result of the work of many people who made the code better - ilyes kooli - gr1ev0us - mlazovla + - Alejandro Diaz Torres - Max Beutel - Antanas Arvasevicius - Pierre Dudoret @@ -1152,6 +1164,7 @@ Symfony is the result of the work of many people who made the code better - Ken Marfilla (marfillaster) - benatespina (benatespina) - Denis Kop + - HypeMC - Jean-Guilhem Rouel (jean-gui) - jfcixmedia - Dominic Tubach @@ -1167,6 +1180,7 @@ Symfony is the result of the work of many people who made the code better - Soner Sayakci - hugofonseca (fonsecas72) - Marc Duboc (icemad) + - Matthias Krauser (mkrauser) - Martynas Narbutas - Toon Verwerft (veewee) - Bailey Parker @@ -1216,6 +1230,7 @@ Symfony is the result of the work of many people who made the code better - Mathias STRASSER (roukmoute) - Thomason, James - Gordienko Vladislav + - marie - Viacheslav Sychov - Alexandre Quercia (alquerci) - Helmut Hummel (helhum) @@ -1307,8 +1322,8 @@ Symfony is the result of the work of many people who made the code better - Ilia (aliance) - Chris McCafferty (cilefen) - Mo Di (modi) - - Tien Vo (tienvx) - Pablo Schläpfer + - SuRiKmAn - Gert de Pagter - Jelte Steijaert (jelte) - David Négrier (moufmouf) @@ -1319,11 +1334,13 @@ Symfony is the result of the work of many people who made the code better - Alex Vasilchenko - sez-open - Xavier Coureau + - fruty - ConneXNL - Aharon Perkel - matze - Rubén Calvo (rubencm) - Abdul.Mohsen B. A. A + - Swen van Zanten - Benoît Burnichon - pthompson - Malaney J. Hill @@ -1360,6 +1377,7 @@ Symfony is the result of the work of many people who made the code better - sl_toto (sl_toto) - Walter Dal Mut (wdalmut) - abluchet + - Ruud Arentsen - Matthieu - Albin Kerouaton - Sébastien HOUZÉ @@ -1385,11 +1403,11 @@ Symfony is the result of the work of many people who made the code better - Constantine Shtompel - Jules Lamur - Renato Mendes Figueiredo + - pdommelen - Eric Stern - ShiraNai7 - Cedrick Oka - Antal Áron (antalaron) - - Markus Fasselt (digilist) - Vašek Purchart (vasek-purchart) - Janusz Jabłoński (yanoosh) - Fleuv @@ -1408,6 +1426,7 @@ Symfony is the result of the work of many people who made the code better - Andreas Frömer - Philip Frank - Lance McNearney + - Jeroen Spee (jeroens) - Giorgio Premi - ncou - Ian Carroll @@ -1420,6 +1439,7 @@ Symfony is the result of the work of many people who made the code better - Luis Galeas - Martin Pärtel - Bastien Jaillot (bastnic) + - Daniel Rotter (danrot) - Frédéric Bouchery (fbouchery) - Patrick Daley (padrig) - Xavier Briand (xavierbriand) @@ -1440,7 +1460,6 @@ Symfony is the result of the work of many people who made the code better - Daniel González Zaballos (dem3trio) - Emmanuel Vella (emmanuel.vella) - Guillaume BRETOU (guiguiboy) - - Dāvis Zālītis (k0d3r1s) - Carsten Nielsen (phreaknerd) - Roger Guasch (rogerguasch) - Jay Severson @@ -1559,6 +1578,7 @@ Symfony is the result of the work of many people who made the code better - povilas - Gavin Staniforth - Alessandro Tagliapietra (alex88) + - Andy Palmer (andyexeter) - Biji (biji) - Jérôme Tanghe (deuchnord) - Alex Teterin (errogaht) @@ -1606,7 +1626,6 @@ Symfony is the result of the work of many people who made the code better - Jibé Barth (jibbarth) - Matthew Foster (mfoster) - Reyo Stallenberg (reyostallenberg) - - Ruben Jacobs (rubenj) - Paul Seiffert (seiffert) - Vasily Khayrulin (sirian) - Stefan Koopmanschap (skoop) @@ -1648,6 +1667,7 @@ Symfony is the result of the work of many people who made the code better - Peter Bex - Manatsawin Hanmongkolchai - Gunther Konig + - Joe Springe - Mickael GOETZ - Maciej Schmidt - Dennis Væversted @@ -1677,12 +1697,12 @@ Symfony is the result of the work of many people who made the code better - me_shaon - 蝦米 - Grayson Koonce (breerly) - - Mardari Dorel (dorumd) - Andrey Helldar (helldar) - Karim Cassam Chenaï (ka) - Maksym Slesarenko (maksym_slesarenko) - Michal Kurzeja (mkurzeja) - Nicolas Bastien (nicolas_bastien) + - Peter Bowyer (pbowyer) - Nikola Svitlica (thecelavi) - Denis (yethee) - Andrew Zhilin (zhil) @@ -1760,7 +1780,6 @@ Symfony is the result of the work of many people who made the code better - Yannick Warnier (ywarnier) - Kevin Decherf - Jason Woods - - Oleg Andreyev - klemens - dened - Dmitry Korotovsky @@ -1777,6 +1796,7 @@ Symfony is the result of the work of many people who made the code better - taiiiraaa - Trevor Suarez - gedrox + - Bohan Yang - Alan Bondarchuk - Joe Bennett - dropfen @@ -1810,6 +1830,7 @@ Symfony is the result of the work of many people who made the code better - Jan Marek (janmarek) - Mark de Haan (markdehaan) - Dan Patrick (mdpatrick) + - Geoffrey Monte (numerogeek) - Pedro Magalhães (pmmaga) - Rares Vlaseanu (raresvla) - tante kinast (tante) @@ -1907,6 +1928,7 @@ Symfony is the result of the work of many people who made the code better - hainey - Juan M Martínez - Gilles Gauthier + - Pavinthan - ddebree - Kuba Werłos - Gyula Szucs @@ -2032,11 +2054,13 @@ Symfony is the result of the work of many people who made the code better - jc - BenjaminBeck - Aurelijus Rožėnas + - Beno!t POLASZEK - Jordan Hoff - znerol - Christian Eikermann - Kai Eichinger - Antonio Angelino + - Jens Schulze - Matt Fields - Niklas Keller - Andras Debreczeni @@ -2115,6 +2139,7 @@ Symfony is the result of the work of many people who made the code better - Lebnik - nsbx - Shude + - Richard Hodgson - Ondřej Führer - Sema - Elan Ruusamäe @@ -2134,6 +2159,7 @@ Symfony is the result of the work of many people who made the code better - Benjamin Long - Ben Miller - Peter Gribanov + - Matteo Galli - kwiateusz - jspee - Ilya Bulakh @@ -2172,6 +2198,7 @@ Symfony is the result of the work of many people who made the code better - Lin Lu - arduanov - sualko + - Molkobain - Bilge - ADmad - Nicolas Roudaire @@ -2282,6 +2309,7 @@ Symfony is the result of the work of many people who made the code better - Wouter Sioen (wouter_sioen) - Xavier Amado (xamado) - Jesper Søndergaard Pedersen (zerrvox) + - Alexander Menshchikov (zmey_kk) - Florent Cailhol - szymek - Kovacs Nicolas From 83b90c2e003c460db7407829484a0c85f28f8043 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 16:41:56 +0200 Subject: [PATCH 07/26] updated VERSION for 3.4.32 --- 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 8ad08b9c7d..2f6a6e4612 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.32-DEV'; + const VERSION = '3.4.32'; const VERSION_ID = 30432; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; const RELEASE_VERSION = 32; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From e3624e7086ba300c5043bd5cec981a00975b4129 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 16:51:28 +0200 Subject: [PATCH 08/26] bumped Symfony version to 3.4.33 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 2f6a6e4612..325ef4d443 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.32'; - const VERSION_ID = 30432; + const VERSION = '3.4.33-DEV'; + const VERSION_ID = 30433; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 32; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 33; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 9371e9c72ce1c3745fc3f403138df45f58d0a11e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 17:06:24 +0200 Subject: [PATCH 09/26] updated CHANGELOG for 4.3.5 --- CHANGELOG-4.3.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/CHANGELOG-4.3.md b/CHANGELOG-4.3.md index 9d60553f2e..0d18622314 100644 --- a/CHANGELOG-4.3.md +++ b/CHANGELOG-4.3.md @@ -7,6 +7,91 @@ in 4.3 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1 +* 4.3.5 (2019-10-07) + + * bug #33742 [Crawler] document $default as string|null (nicolas-grekas) + * bug #32308 [Messenger] DoctrineTransport: ensure auto setup is only done once (bendavies) + * bug #33871 [HttpClient] bugfix exploding values of headers (michaljusiega) + * bug #33834 [Validator] Fix ValidValidator group cascading usage (fancyweb) + * bug #33863 [Routing] gracefully handle docref_root ini setting (nicolas-grekas) + * bug #33846 [Cache] give 100ms before starting the expiration countdown (nicolas-grekas) + * bug #33853 [HttpClient] fix "no_proxy" option ignored in NativeHttpClient (Harry-Dunne) + * bug #33841 [VarDumper] fix dumping uninitialized SplFileInfo (nicolas-grekas) + * bug #33842 [Cache] fix logger usage in CacheTrait::doGet() (nicolas-grekas) + * bug #33835 [Workflow] Fixed BC break on WorkflowInterface (lyrixx) + * bug #33799 [Security]: Don't let falsy usernames slip through impersonation (j4nr6n) + * bug #33814 [HttpFoundation] Check if data passed to SessionBagProxy::initialize is an array (mynameisbogdan) + * bug #33744 [DI] Add CSV env var processor tests / support PHP 7.4 (ro0NL) + * bug #33805 [FrameworkBundle] Fix wrong returned status code in ConfigDebugCommand (jschaedl) + * bug #33781 [AnnotationCacheWarmer] add RedirectController to annotation cache (jenschude) + * bug #33777 Fix the :only-of-type pseudo class selector (jakzal) + * bug #32051 [Serializer] Add CsvEncoder tests for PHP 7.4 (ro0NL) + * feature #33776 Copy phpunit.xsd to a predictable path (julienfalque) + * bug #33759 [Security/Http] fix parsing X509 emailAddress (nicolas-grekas) + * bug #33733 [Serializer] fix denormalization of string-arrays with only one element (mkrauser) + * bug #33754 [Cache] fix known tag versions ttl check (SwenVanZanten) + * bug #33646 [HttpFoundation] allow additinal characters in not raw cookies (marie) + * bug #33748 [Console] Do not include hidden commands in suggested alternatives (m-vo) + * bug #33625 [DependencyInjection] Fix wrong exception when service is synthetic (k0d3r1s) + * bug #32979 [Messenger] return empty envelopes when RetryableException occurs (surikman) + * bug #32522 [Validator] Accept underscores in the URL validator, as the URL will load (battye) + * bug #32437 Fix toolbar load when GET params are present in "_wdt" route (Molkobain) + * bug #32925 [Translation] Collect original locale in case of fallback translation (digilist) + * bug #33691 [HttpClient] fix race condition when reading response with informational status (nicolas-grekas) + * bug #33727 [HttpClient] workaround bad Content-Length sent by old libcurl (nicolas-grekas) + * bug #31198 [FrameworkBundle] Fix framework bundle lock configuration not working as expected (HypeMC) + * bug #33719 [Cache] dont override native Memcached options (nicolas-grekas) + * bug #33703 [Cache] fail gracefully when locking is not supported (nicolas-grekas) + * bug #33713 Fix exceptions (PDOException) error code type (fruty) + * bug #32335 [Form] Names for buttons should start with lowercase (mcfedr) + * bug #33706 [Mailer][Messenger] ensure legacy event dispatcher compatibility (xabbuh) + * bug #33688 Add missing row_attr option to FormType (mcsky) + * bug #33693 [Security] use LegacyEventDispatcherProxy (dmaicher) + * bug #33675 [PhpUnit] Fix usleep mock return value (fabpot) + * bug #33652 [Cache] skip igbinary on PHP 7.4.0 (nicolas-grekas) + * bug #33643 [HttpClient] fix throwing HTTP exceptions when the 1st chunk is emitted (nicolas-grekas) + * bug #33618 fix tests depending on other components' tests (xabbuh) + * bug #33626 [PropertyInfo] ensure compatibility with type resolver 0.5 (xabbuh) + * bug #33620 [Twig] Fix Twig config extra keys (fabpot) + * bug #33600 [Messenger] Fix exception message of failed message is dropped on retry (tienvx) + * bug #33601 [HttpClient] Add default value for Accept header (numerogeek) + * bug #33340 [Finder] Adjust regex to correctly match comments in gitignore contents (Jeroeny) + * bug #33588 [PropertyInfo] ensure compatibility with type resolver 0.5 (xabbuh) + * bug #33575 [WebProfilerBundle] Fix time panel legend buttons (fancyweb) + * bug #33571 [Inflector] add support 'see' to 'ee' for singularize 'fees' to 'fee' (maxhelias) + * bug #32763 [Console] Get dimensions from stty on windows if possible (rtek) + * bug #33570 Fixed cache pools affecting each other due to an overwritten seed variable (roed) + * bug #33517 [Yaml] properly catch legacy tag syntax usages (xabbuh) + * bug #33546 [DependencyInjection] Accept existing interfaces as valid named args (fancyweb) + * bug #33547 [HttpClient] Re-enable Server Push support (dunglas) + * bug #33521 Fixed incompatibility between ServiceSubscriberTrait and classes with protected $container property (a-menshchikov) + * bug #33518 [Yaml] don't dump a scalar tag value on its own line (xabbuh) + * bug #33505 [HttpClient] fallbackto CURLMOPT_MAXCONNECTS when CURLMOPT_MAX_HOST_CONNECTIONS is not available (nicolas-grekas) + * bug #32818 [HttpKernel] Fix getFileLinkFormat() to avoid returning the wrong URL in Profiler (Arman-Hosseini) + * bug #33487 [HttpKernel] Fix Apache mod_expires Session Cache-Control issue (pbowyer) + * bug #33469 [FrameworkBundle] Fixed suggested package for missing server:dump command (lyrixx) + * bug #31964 [Router] routing cache crash when using generator_class (dFayet) + * bug #33481 [Messenger] fix empty amqp body returned as false (Tobion) + * bug #33387 [Mailer] maintain sender/recipient name in SMTP envelopes (xabbuh) + * bug #33449 Fix gmail relay (Beno!t POLASZEK) + * bug #33391 [HttpClient] fix support for 103 Early Hints and other informational status codes (nicolas-grekas) + * bug #33444 [HttpClient] improve handling of HTTP/2 PUSH, disable it by default (nicolas-grekas) + * bug #33435 [Validator] Only handle numeric values in DivisibleBy (fancyweb) + * bug #33437 Fix #33427 (sylfabre) + * bug #33439 [Validator] Sync string to date behavior and throw a better exception (fancyweb) + * bug #33436 [DI] fix support for "!tagged_locator foo" (nicolas-grekas) + * bug #32903 [PHPUnit Bridge] Avoid registering listener twice (alexpott) + * bug #33432 [Mailer] Fix Mailgun support when a response is not JSON as expected (fabpot) + * bug #33402 [Finder] Prevent unintentional file locks in Windows (jspringe) + * bug #33376 [Mailer] Remove the default dispatcher in AbstractTransport (fabpot) + * bug #33357 [FrameworkBundle] Fix about command not showing .env vars (brentybh) + * bug #33396 Fix #33395 PHP 5.3 compatibility (kylekatarnls) + * bug #33363 [Routing] fix static route reordering when a previous dynamic route conflicts (nicolas-grekas) + * bug #33385 [Console] allow Command::getName() to return null (nicolas-grekas) + * bug #33353 Return null as Expire header if it was set to null (danrot) + * bug #33382 [ProxyManager] remove ProxiedMethodReturnExpression polyfill (nicolas-grekas) + * bug #33377 [Yaml] fix dumping not inlined scalar tag values (xabbuh) + * 4.3.4 (2019-08-26) * bug #33335 [DependencyInjection] Fixed the `getServiceIds` implementation to always return aliases (pdommelen) From a87f8f983abba1e76c2641120bd50c485a1d659e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 17:06:41 +0200 Subject: [PATCH 10/26] updated VERSION for 4.3.5 --- 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 da2c972120..7d18d221d5 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,12 +73,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.3.5-DEV'; + const VERSION = '4.3.5'; const VERSION_ID = 40305; const MAJOR_VERSION = 4; const MINOR_VERSION = 3; const RELEASE_VERSION = 5; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2020'; const END_OF_LIFE = '07/2020'; From a4f90e8258e285dbca3b2122ef059000ec5ca8d8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Oct 2019 17:19:44 +0200 Subject: [PATCH 11/26] bumped Symfony version to 4.3.6 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7d18d221d5..cf789426e3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,12 +73,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.3.5'; - const VERSION_ID = 40305; + const VERSION = '4.3.6-DEV'; + const VERSION_ID = 40306; const MAJOR_VERSION = 4; const MINOR_VERSION = 3; - const RELEASE_VERSION = 5; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 6; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2020'; const END_OF_LIFE = '07/2020'; From cdc7446051a0e2c80bab68751f4ecd3d1c8420fd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 1 Oct 2019 09:48:14 +0200 Subject: [PATCH 12/26] [DI] enable improved syntax for defining method calls in Yaml --- .../DependencyInjection/CHANGELOG.md | 1 + .../Loader/YamlFileLoader.php | 38 ++++++++++++++++--- .../Tests/Fixtures/yaml/alt_call.yaml | 5 +++ .../Tests/Loader/YamlFileLoaderTest.php | 15 ++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7171cb882d..c90cfa7471 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * added support for binding iterable and tagged services * made singly-implemented interfaces detection be scoped by file * added ability to define a static priority method for tagged service + * added support for improved syntax to define method calls in Yaml 4.3.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 8a47fae60b..b219fcc801 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -459,20 +459,48 @@ class YamlFileLoader extends FileLoader throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - foreach ($service['calls'] as $call) { + foreach ($service['calls'] as $k => $call) { + if (!\is_array($call) && (!\is_string($k) || !$call instanceof TaggedValue)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s": expected map or array, %s given in %s.', $id, $call instanceof TaggedValue ? '!'.$call->getTag() : \gettype($call), $file)); + } + + if (\is_string($k)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s", did you forgot a leading dash before "%s: ..." in %s?', $id, $k, $file)); + } + if (isset($call['method'])) { $method = $call['method']; - $args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : []; + $args = $call['arguments'] ?? []; $returnsClone = $call['returns_clone'] ?? false; } else { - $method = $call[0]; - $args = isset($call[1]) ? $this->resolveServices($call[1], $file) : []; - $returnsClone = $call[2] ?? false; + if (1 === \count($call) && \is_string(key($call))) { + $method = key($call); + $args = $call[$method]; + + if ($args instanceof TaggedValue) { + if ('returns_clone' !== $args->getTag()) { + throw new InvalidArgumentException(sprintf('Unsupported tag "!%s", did you mean "!returns_clone" for service "%s" in %s?', $args->getTag(), $id, $file)); + } + + $returnsClone = true; + $args = $args->getValue(); + } else { + $returnsClone = false; + } + } elseif (empty($call[0])) { + throw new InvalidArgumentException(sprintf('Invalid call for service "%s": the method must be defined as the first index of an array or as the only key of a map in %s.', $id, $file)); + } else { + $method = $call[0]; + $args = $call[1] ?? []; + $returnsClone = $call[2] ?? false; + } } if (!\is_array($args)) { throw new InvalidArgumentException(sprintf('The second parameter for function call "%s" must be an array of its arguments for service "%s" in %s. Check your YAML syntax.', $method, $id, $file)); } + + $args = $this->resolveServices($args, $file); $definition->addMethodCall($method, $args, $returnsClone); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml new file mode 100644 index 0000000000..26cf9e628c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/alt_call.yaml @@ -0,0 +1,5 @@ +services: + foo: + calls: + - foo: [1, 2, 3] + - bar: !returns_clone [1, 2, 3] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 2e116132a3..e01f41d139 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -900,4 +900,19 @@ class YamlFileLoaderTest extends TestCase $this->assertSame(Prototype\SinglyImplementedInterface\Adapter\Adapter::class, (string) $alias); } + + public function testAlternativeMethodCalls() + { + $container = new ContainerBuilder(); + + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('alt_call.yaml'); + + $expected = [ + ['foo', [1, 2, 3]], + ['bar', [1, 2, 3], true], + ]; + + $this->assertSame($expected, $container->getDefinition('foo')->getMethodCalls()); + } } From 78b515f049105e7c9dfeb8877e6137fb3efca0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Ma=C5=A1a?= Date: Mon, 7 Oct 2019 13:35:44 +0200 Subject: [PATCH 13/26] Prevent ProgressBar redraw when message is same --- .../Component/Console/Helper/ProgressBar.php | 12 ++++++++--- .../Console/Tests/Helper/ProgressBarTest.php | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 3751439fa3..03a7696bfb 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -46,7 +46,7 @@ final class ProgressBar private $messages = []; private $overwrite = true; private $terminal; - private $firstRun = true; + private $previousMessage; private static $formatters; private static $formats; @@ -432,8 +432,14 @@ final class ProgressBar */ private function overwrite(string $message): void { + if ($this->previousMessage === $message) { + return; + } + + $originalMessage = $message; + if ($this->overwrite) { - if (!$this->firstRun) { + if (null !== $this->previousMessage) { if ($this->output instanceof ConsoleSectionOutput) { $lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1; $this->output->clear($lines); @@ -451,7 +457,7 @@ final class ProgressBar $message = PHP_EOL.$message; } - $this->firstRun = false; + $this->previousMessage = $originalMessage; $this->lastWriteTime = microtime(true); $this->output->write($message); diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index 877b1dfd19..7796fa6881 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -187,7 +187,6 @@ class ProgressBarTest extends TestCase { $expected = ' 0/10 [>---------------------------] 0%'. - $this->generateOutput(' 10/10 [============================] 100%'). $this->generateOutput(' 10/10 [============================] 100%') ; @@ -296,7 +295,6 @@ class ProgressBarTest extends TestCase rewind($output->getStream()); $this->assertEquals( ' 0/50 [>---------------------------] 0%'. - $this->generateOutput(' 0/50 [>---------------------------] 0%'). $this->generateOutput(' 1/50 [>---------------------------] 2%'). $this->generateOutput(' 2/50 [=>--------------------------] 4%'), stream_get_contents($output->getStream()) @@ -318,7 +316,6 @@ class ProgressBarTest extends TestCase rewind($output->getStream()); $this->assertEquals( ' 0/50 [>---------------------------] 0%'. - $this->generateOutput(' 0/50 [>---------------------------] 0%'). $this->generateOutput(' 1/50 [>---------------------------] 2%'). $this->generateOutput(' 2/50 [=>--------------------------]'), stream_get_contents($output->getStream()) @@ -340,7 +337,6 @@ class ProgressBarTest extends TestCase rewind($output->getStream()); $this->assertEquals( ' 0/50 [>---------------------------] 0%'.PHP_EOL. - "\x1b[1A\x1b[0J".' 0/50 [>---------------------------] 0%'.PHP_EOL. "\x1b[1A\x1b[0J".' 1/50 [>---------------------------] 2%'.PHP_EOL. "\x1b[1A\x1b[0J".' 2/50 [=>--------------------------] 4%'.PHP_EOL, stream_get_contents($output->getStream()) @@ -434,7 +430,6 @@ class ProgressBarTest extends TestCase rewind($output->getStream()); $this->assertEquals( ' 0/50 [>---------------------------] 0%'. - $this->generateOutput(' 0/50 [>---------------------------] 0%'). $this->generateOutput(' 1/50 [>---------------------------] 2%'). $this->generateOutput(' 15/50 [========>-------------------] 30%'). $this->generateOutput(' 25/50 [==============>-------------] 50%'), @@ -541,7 +536,6 @@ class ProgressBarTest extends TestCase rewind($output->getStream()); $this->assertEquals( ' 0/200 [>---------------------------] 0%'. - $this->generateOutput(' 0/200 [>---------------------------] 0%'). $this->generateOutput(' 199/200 [===========================>] 99%'). $this->generateOutput(' 200/200 [============================] 100%'), stream_get_contents($output->getStream()) @@ -888,7 +882,6 @@ class ProgressBarTest extends TestCase $this->assertEquals( ' 0/2 [>---------------------------] 0%'. $this->generateOutput(' 1/2 [==============>-------------] 50%'). - $this->generateOutput(' 2/2 [============================] 100%'). $this->generateOutput(' 2/2 [============================] 100%'), stream_get_contents($output->getStream()) ); @@ -996,4 +989,18 @@ class ProgressBarTest extends TestCase stream_get_contents($output->getStream()) ); } + + public function testNoWriteWhenMessageIsSame(): void + { + $bar = new ProgressBar($output = $this->getOutputStream(), 2); + $bar->start(); + $bar->advance(); + $bar->display(); + rewind($output->getStream()); + $this->assertEquals( + ' 0/2 [>---------------------------] 0%'. + $this->generateOutput(' 1/2 [==============>-------------] 50%'), + stream_get_contents($output->getStream()) + ); + } } From 0db883888c8ad1a17a0141b307f546fff5541328 Mon Sep 17 00:00:00 2001 From: Ogbemudia Terry Osayawe Date: Mon, 7 Oct 2019 17:36:51 +0200 Subject: [PATCH 14/26] Add the missing translations for the Swedish ("sv") locale --- .../Resources/translations/validators.sv.xlf | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index b3e8f0f42f..bf7da2f06c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -334,6 +334,38 @@ This value should be valid JSON. Detta värde ska vara giltig JSON. + + This collection should contain only unique elements. + Denna samling bör endast innehålla unika element. + + + This value should be positive. + Detta värde bör vara positivt. + + + This value should be either positive or zero. + Detta värde bör vara antingen positivt eller noll. + + + This value should be negative. + Detta värde bör vara negativt. + + + This value should be either negative or zero. + Detta värde bör vara antingen negativt eller noll. + + + This value is not a valid timezone. + Detta värde är inte en giltig tidszon. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Det här lösenordet har läckt ut vid ett dataintrång, det får inte användas. Använd ett annat lösenord. + + + This value should be between {{ min }} and {{ max }}. + Detta värde bör ligga mellan {{ min }} och {{ max }}. + From ca3fb258bf9665cbac08c635e3f8619a03f64226 Mon Sep 17 00:00:00 2001 From: bogdan Date: Tue, 8 Oct 2019 04:19:00 +0300 Subject: [PATCH 15/26] [HttpKernel] fix $dotenvVars in data collector --- .../HttpKernel/DataCollector/RequestDataCollector.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 32624c963f..3f6150ba9f 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -80,9 +80,9 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter } $dotenvVars = []; - foreach (explode(',', getenv('SYMFONY_DOTENV_VARS')) as $name) { - if ('' !== $name && false !== $value = getenv($name)) { - $dotenvVars[$name] = $value; + foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) { + if ('' !== $name && isset($_ENV[$name])) { + $dotenvVars[$name] = $_ENV[$name]; } } From 5baa3ea8d4e6ec99d9813df3dfd47cca8e598726 Mon Sep 17 00:00:00 2001 From: Harald Tollefsen Date: Tue, 8 Oct 2019 11:13:14 +0200 Subject: [PATCH 16/26] Adds missing translations for no nb --- .../Resources/translations/validators.nb.xlf | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index db534528d1..bfa9b1284e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -334,6 +334,38 @@ This value should be valid JSON. Verdien er ikke gyldig JSON. + + This collection should contain only unique elements. + Samlingen kan kun inneholde unike elementer. + + + This value should be positive. + Denne verdien må være positiv. + + + This value should be either positive or zero. + Denne verdien må være positiv eller null. + + + This value should be negative. + Denne verdien må være negativ. + + + This value should be either negative or zero. + Denne verdien må være negativ eller null. + + + This value is not a valid timezone. + Verdien er ikke en gyldig tidssone. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Dette passordet er lekket i et datainnbrudd, det må ikke tas i bruk. Vennligst bruk et annet passord. + + + This value should be between {{ min }} and {{ max }}. + Verdien må være mellom {{ min }} og {{ max }}. + From 3d38c58b42a242d1eaadb7905ffedb6dc2e9889c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Wed, 25 Sep 2019 18:03:38 +0200 Subject: [PATCH 17/26] [Cache] Improve RedisTagAwareAdapter invalidation logic & requirements --- .../Cache/Adapter/RedisTagAwareAdapter.php | 117 ++++++++++-------- src/Symfony/Component/Cache/CHANGELOG.md | 2 + .../PredisTagAwareRedisClusterAdapterTest.php | 35 ------ .../Component/Cache/Traits/RedisTrait.php | 35 ++++-- 4 files changed, 92 insertions(+), 97 deletions(-) delete mode 100644 src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php index 71230ad69b..7bba834294 100644 --- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php @@ -11,33 +11,32 @@ namespace Symfony\Component\Cache\Adapter; -use Predis; use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Connection\Aggregate\PredisCluster; use Predis\Response\Status; -use Symfony\Component\Cache\CacheItem; -use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\RedisTrait; /** - * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using sPOP. + * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using RENAME+SMEMBERS. * * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache * relationship survives eviction (cache cleanup when Redis runs out of memory). * * Requirements: - * - Server: Redis 3.2+ - * - Client: PHP Redis 3.1.3+ OR Predis - * - Redis Server(s) configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory + * - Client: PHP Redis or Predis + * Note: Due to lack of RENAME support it is NOT recommended to use Cluster on Predis, instead use phpredis. + * - Server: Redis 2.8+ + * Configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory * * Design limitations: - * - Max 2 billion cache keys per cache tag - * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 2 billion cache items as well + * - Max 4 billion cache keys per cache tag as limited by Redis Set datatype. + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also. * * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies. * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype. - * @see https://redis.io/commands/spop Documentation for sPOP operation, capable of retriving AND emptying a Set at once. * * @author Nicolas Grekas * @author André Rømcke @@ -46,11 +45,6 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter { use RedisTrait; - /** - * Redis "Set" can hold more than 4 billion members, here we limit ourselves to PHP's > 2 billion max int (32Bit). - */ - private const POP_MAX_LIMIT = 2147483647 - 1; - /** * Limits for how many keys are deleted in batch. */ @@ -62,26 +56,18 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter */ private const DEFAULT_CACHE_TTL = 8640000; - /** - * @var bool|null - */ - private $redisServerSupportSPOP = null; - /** * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient The redis client * @param string $namespace The default namespace * @param int $defaultLifetime The default lifetime - * - * @throws \Symfony\Component\Cache\Exception\LogicException If phpredis with version lower than 3.1.3. */ public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); - - // Make sure php-redis is 3.1.3 or higher configured for Redis classes - if (!$this->redis instanceof \Predis\ClientInterface && version_compare(phpversion('redis'), '3.1.3', '<')) { - throw new LogicException('RedisTagAwareAdapter requires php-redis 3.1.3 or higher, alternatively use predis/predis'); + if ($redisClient instanceof \Predis\ClientInterface && $redisClient->getConnection() instanceof ClusterInterface && !$redisClient->getConnection() instanceof PredisCluster) { + throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, \get_class($redisClient->getConnection()))); } + + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); } /** @@ -121,7 +107,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter continue; } // setEx results - if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) { + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { $failed[] = $id; } } @@ -138,9 +124,10 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter return true; } - $predisCluster = $this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface; + $predisCluster = $this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof PredisCluster; $this->pipeline(static function () use ($ids, $tagData, $predisCluster) { if ($predisCluster) { + // Unlike phpredis, Predis does not handle bulk calls for us against cluster foreach ($ids as $id) { yield 'del' => [$id]; } @@ -161,46 +148,76 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter */ protected function doInvalidate(array $tagIds): bool { - if (!$this->redisServerSupportSPOP()) { + if (!$this->redis instanceof \Predis\ClientInterface || !$this->redis->getConnection() instanceof PredisCluster) { + $movedTagSetIds = $this->renameKeys($this->redis, $tagIds); + } else { + $clusterConnection = $this->redis->getConnection(); + $tagIdsByConnection = new \SplObjectStorage(); + $movedTagSetIds = []; + + foreach ($tagIds as $id) { + $connection = $clusterConnection->getConnectionByKey($id); + $slot = $tagIdsByConnection[$connection] ?? $tagIdsByConnection[$connection] = new \ArrayObject(); + $slot[] = $id; + } + + foreach ($tagIdsByConnection as $connection) { + $slot = $tagIdsByConnection[$connection]; + $movedTagSetIds = array_merge($movedTagSetIds, $this->renameKeys(new $this->redis($connection, $this->redis->getOptions()), $slot->getArrayCopy())); + } + } + + // No Sets found + if (!$movedTagSetIds) { return false; } - // Pop all tag info at once to avoid race conditions - $tagIdSets = $this->pipeline(static function () use ($tagIds) { - foreach ($tagIds as $tagId) { - // Client: Predis or PHP Redis 3.1.3+ (https://github.com/phpredis/phpredis/commit/d2e203a6) - // Server: Redis 3.2 or higher (https://redis.io/commands/spop) - yield 'sPop' => [$tagId, self::POP_MAX_LIMIT]; + // Now safely take the time to read the keys in each set and collect ids we need to delete + $tagIdSets = $this->pipeline(static function () use ($movedTagSetIds) { + foreach ($movedTagSetIds as $movedTagId) { + yield 'sMembers' => [$movedTagId]; } }); - // Flatten generator result from pipeline, ignore keys (tag ids) - $ids = array_unique(array_merge(...iterator_to_array($tagIdSets, false))); + // Return combination of the temporary Tag Set ids and their values (cache ids) + $ids = array_merge($movedTagSetIds, ...iterator_to_array($tagIdSets, false)); // Delete cache in chunks to avoid overloading the connection - foreach (array_chunk($ids, self::BULK_DELETE_LIMIT) as $chunkIds) { + foreach (array_chunk(array_unique($ids), self::BULK_DELETE_LIMIT) as $chunkIds) { $this->doDelete($chunkIds); } return true; } - private function redisServerSupportSPOP(): bool + /** + * Renames several keys in order to be able to operate on them without risk of race conditions. + * + * Filters out keys that do not exist before returning new keys. + * + * @see https://redis.io/commands/rename + * @see https://redis.io/topics/cluster-spec#keys-hash-tags + * + * @return array Filtered list of the valid moved keys (only those that existed) + */ + private function renameKeys($redis, array $ids): array { - if (null !== $this->redisServerSupportSPOP) { - return $this->redisServerSupportSPOP; - } + $newIds = []; + $uniqueToken = bin2hex(random_bytes(10)); - foreach ($this->getHosts() as $host) { - $info = $host->info('Server'); - $info = isset($info['Server']) ? $info['Server'] : $info; - if (version_compare($info['redis_version'], '3.2', '<')) { - CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as '.$info['redis_version']); + $results = $this->pipeline(static function () use ($ids, $uniqueToken) { + foreach ($ids as $id) { + yield 'rename' => [$id, '{'.$id.'}'.$uniqueToken]; + } + }, $redis); - return $this->redisServerSupportSPOP = false; + foreach ($results as $id => $result) { + if (true === $result || ($result instanceof Status && Status::get('OK') === $result)) { + // Only take into account if ok (key existed), will be false on phpredis if it did not exist + $newIds[] = '{'.$id.'}'.$uniqueToken; } } - return $this->redisServerSupportSPOP = true; + return $newIds; } } diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md index 136953fe27..bbe316830b 100644 --- a/src/Symfony/Component/Cache/CHANGELOG.md +++ b/src/Symfony/Component/Cache/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * added support for connecting to Redis Sentinel clusters * added argument `$prefix` to `AdapterInterface::clear()` + * improved `RedisTagAwareAdapter` to support Redis server >= 2.8 and up to 4B items per tag + * [BC BREAK] `RedisTagAwareAdapter` is not compatible with `RedisCluster` from `Predis` anymore, use `phpredis` instead 4.3.0 ----- diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php deleted file mode 100644 index 8357fffe39..0000000000 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; -use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; - -class PredisTagAwareRedisClusterAdapterTest extends PredisRedisClusterAdapterTest -{ - use TagAwareTestTrait; - - protected function setUp(): void - { - parent::setUp(); - $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; - } - - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface - { - $this->assertInstanceOf(\Predis\Client::class, self::$redis); - $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); - - return $adapter; - } -} diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index f3e7a072d4..fbc8f6c69f 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -55,9 +55,17 @@ trait RedisTrait if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } + if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\ClientInterface && !$redisClient instanceof RedisProxy && !$redisClient instanceof RedisClusterProxy) { throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, %s given.', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient))); } + + if ($redisClient instanceof \Predis\ClientInterface && $redisClient->getOptions()->exceptions) { + $options = clone $redisClient->getOptions(); + \Closure::bind(function () { $this->options['exceptions'] = false; }, $options, $options)(); + $redisClient = new $redisClient($redisClient->getConnection(), $options); + } + $this->redis = $redisClient; $this->marshaller = $marshaller ?? new DefaultMarshaller(); } @@ -277,6 +285,7 @@ trait RedisTrait $params['replication'] = true; $hosts[0] += ['alias' => 'master']; } + $params['exceptions'] = false; $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions)); if (isset($params['redis_sentinel'])) { @@ -414,8 +423,9 @@ trait RedisTrait } } }); + foreach ($results as $id => $result) { - if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) { + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { $failed[] = $id; } } @@ -423,31 +433,32 @@ trait RedisTrait return $failed; } - private function pipeline(\Closure $generator): \Generator + private function pipeline(\Closure $generator, $redis = null): \Generator { $ids = []; + $redis = $redis ?? $this->redis; - if ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof RedisCluster)) { + if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof RedisCluster)) { // phpredis & predis don't support pipelining with RedisCluster // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining // see https://github.com/nrk/predis/issues/267#issuecomment-123781423 $results = []; foreach ($generator() as $command => $args) { - $results[] = $this->redis->{$command}(...$args); + $results[] = $redis->{$command}(...$args); $ids[] = $args[0]; } - } elseif ($this->redis instanceof \Predis\ClientInterface) { - $results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) { + } elseif ($redis instanceof \Predis\ClientInterface) { + $results = $redis->pipeline(static function ($redis) use ($generator, &$ids) { foreach ($generator() as $command => $args) { $redis->{$command}(...$args); $ids[] = $args[0]; } }); - } elseif ($this->redis instanceof \RedisArray) { + } elseif ($redis instanceof \RedisArray) { $connections = $results = $ids = []; foreach ($generator() as $command => $args) { - if (!isset($connections[$h = $this->redis->_target($args[0])])) { - $connections[$h] = [$this->redis->_instance($h), -1]; + if (!isset($connections[$h = $redis->_target($args[0])])) { + $connections[$h] = [$redis->_instance($h), -1]; $connections[$h][0]->multi(\Redis::PIPELINE); } $connections[$h][0]->{$command}(...$args); @@ -461,12 +472,12 @@ trait RedisTrait $results[$k] = $connections[$h][$c]; } } else { - $this->redis->multi(\Redis::PIPELINE); + $redis->multi(\Redis::PIPELINE); foreach ($generator() as $command => $args) { - $this->redis->{$command}(...$args); + $redis->{$command}(...$args); $ids[] = $args[0]; } - $results = $this->redis->exec(); + $results = $redis->exec(); } foreach ($ids as $k => $id) { From 1f20f35f74df7c657ca648efb87755416427da82 Mon Sep 17 00:00:00 2001 From: zcodes Date: Wed, 9 Oct 2019 10:12:52 +0800 Subject: [PATCH 18/26] [VarDumper] fix array key error for class SymfonyCaster --- src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php index 78acb90b66..bd8b595a3d 100644 --- a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php @@ -30,7 +30,8 @@ class SymfonyCaster $clone = null; foreach (self::$requestGetters as $prop => $getter) { - if (null === $a[Caster::PREFIX_PROTECTED.$prop]) { + $key = Caster::PREFIX_PROTECTED.$prop; + if (\array_key_exists($key, $a) && null === $a[$key]) { if (null === $clone) { $clone = clone $request; } @@ -44,7 +45,9 @@ class SymfonyCaster public static function castHttpClient($client, array $a, Stub $stub, $isNested) { $multiKey = sprintf("\0%s\0multi", \get_class($client)); - $a[$multiKey] = new CutStub($a[$multiKey]); + if (isset($a[$multiKey])) { + $a[$multiKey] = new CutStub($a[$multiKey]); + } return $a; } From 2dd41e7f2417a41be2d119af276f47fdd0c83c48 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 6 Aug 2019 10:48:05 +0200 Subject: [PATCH 19/26] [Dotenv] support setting default env var values --- src/Symfony/Component/Dotenv/Dotenv.php | 6 +++++- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 2716518979..899f77904f 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -432,7 +432,7 @@ final class Dotenv (?!\() # no opening parenthesis (?P\{)? # optional brace (?P'.self::VARNAME_REGEX.')? # var name - (?P:-[^\}]++)? # optional default value + (?P:[-=][^\}]++)? # optional default value (?P\})? # optional closing brace /x'; @@ -469,6 +469,10 @@ final class Dotenv } $value = substr($matches['default_value'], 2); + + if ('=' === $matches['default_value'][1]) { + $this->values[$name] = $value; + } } if (!$matches['opening_brace'] && isset($matches['closing_brace'])) { diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 7b5f188db8..66d8c4575b 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -166,6 +166,10 @@ class DotenvTest extends TestCase ["FOO=BAR\nBAR=\${NOTDEFINED:-TEST}", ['FOO' => 'BAR', 'BAR' => 'TEST']], ["FOO=\nBAR=\${FOO:-TEST}", ['FOO' => '', 'BAR' => 'TEST']], ["FOO=\nBAR=\$FOO:-TEST}", ['FOO' => '', 'BAR' => 'TEST}']], + ["FOO=BAR\nBAR=\${FOO:=TEST}", ['FOO' => 'BAR', 'BAR' => 'BAR']], + ["FOO=BAR\nBAR=\${NOTDEFINED:=TEST}", ['FOO' => 'BAR', 'NOTDEFINED' => 'TEST', 'BAR' => 'TEST']], + ["FOO=\nBAR=\${FOO:=TEST}", ['FOO' => 'TEST', 'BAR' => 'TEST']], + ["FOO=\nBAR=\$FOO:=TEST}", ['FOO' => 'TEST', 'BAR' => 'TEST}']], ]; if ('\\' !== \DIRECTORY_SEPARATOR) { From eec7e8cc61f3a9adec9ce6741d6ff94a78b94691 Mon Sep 17 00:00:00 2001 From: Yannick Ihmels Date: Wed, 9 Oct 2019 11:59:43 +0200 Subject: [PATCH 20/26] Allow to set cookie_samesite to 'none' --- .../FrameworkBundle/DependencyInjection/Configuration.php | 2 +- .../DependencyInjection/Security/Factory/RememberMeFactory.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 6d6195bbc9..497fb08424 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -542,7 +542,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('cookie_domain')->end() ->enumNode('cookie_secure')->values([true, false, 'auto'])->end() ->booleanNode('cookie_httponly')->defaultTrue()->end() - ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultNull()->end() + ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultNull()->end() ->booleanNode('use_cookies')->end() ->scalarNode('gc_divisor')->end() ->scalarNode('gc_probability')->defaultValue(1)->end() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php index f7500f05e3..28103a3522 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php @@ -144,7 +144,7 @@ class RememberMeFactory implements SecurityFactoryInterface if ('secure' === $name) { $builder->enumNode($name)->values([true, false, 'auto'])->defaultValue('auto' === $value ? null : $value); } elseif ('samesite' === $name) { - $builder->enumNode($name)->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultValue($value); + $builder->enumNode($name)->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultValue($value); } elseif (\is_bool($value)) { $builder->booleanNode($name)->defaultValue($value); } else { From 85f27f270e5b113b84fa7476444e4a5c8149253f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 11:02:41 +0200 Subject: [PATCH 21/26] [Cache] remove implicit dependency on symfony/filesystem --- .../Adapter/FilesystemTagAwareAdapter.php | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php index 0dd81a9970..899e570ef6 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php @@ -16,7 +16,6 @@ use Symfony\Component\Cache\Marshaller\DefaultMarshaller; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; -use Symfony\Component\Filesystem\Filesystem; /** * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. @@ -29,8 +28,8 @@ use Symfony\Component\Filesystem\Filesystem; class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface { use FilesystemTrait { - doSave as doSaveCache; - doDelete as doDeleteCache; + doSave as private doSaveCache; + doDelete as private doDeleteCache; } /** @@ -38,11 +37,6 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune */ private const TAG_FOLDER = 'tags'; - /** - * @var Filesystem|null - */ - private $fs; - public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) { $this->marshaller = $marshaller ?? new DefaultMarshaller(); @@ -57,7 +51,6 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune { $failed = $this->doSaveCache($values, $lifetime); - $fs = $this->getFilesystem(); // Add Tags as symlinks foreach ($addTagData as $tagId => $ids) { $tagFolder = $this->getTagFolder($tagId); @@ -67,12 +60,15 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune } $file = $this->getFile($id); - $fs->symlink($file, $this->getFile($id, true, $tagFolder)); + + if (!@symlink($file, $this->getFile($id, true, $tagFolder))) { + @unlink($file); + $failed[] = $id; + } } } // Unlink removed Tags - $files = []; foreach ($removeTagData as $tagId => $ids) { $tagFolder = $this->getTagFolder($tagId); foreach ($ids as $id) { @@ -80,10 +76,9 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune continue; } - $files[] = $this->getFile($id, false, $tagFolder); + @unlink($this->getFile($id, false, $tagFolder)); } } - $fs->remove($files); return $failed; } @@ -96,15 +91,12 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune $ok = $this->doDeleteCache($ids); // Remove tags - $files = []; - $fs = $this->getFilesystem(); foreach ($tagData as $tagId => $idMap) { $tagFolder = $this->getTagFolder($tagId); foreach ($idMap as $id) { - $files[] = $this->getFile($id, false, $tagFolder); + @unlink($this->getFile($id, false, $tagFolder)); } } - $fs->remove($files); return $ok; } @@ -137,11 +129,6 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune return true; } - private function getFilesystem(): Filesystem - { - return $this->fs ?? $this->fs = new Filesystem(); - } - private function getTagFolder(string $tagId): string { return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR; From b377e41a2c7c11d2bf4e2a077b78b781d542af71 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 14:17:28 +0200 Subject: [PATCH 22/26] [Cache] clean tags folder on invalidation --- .../Adapter/FilesystemTagAwareAdapter.php | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php index 0dd81a9970..077f754aa5 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Cache\Adapter; -use Symfony\Component\Cache\Exception\LogicException; use Symfony\Component\Cache\Marshaller\DefaultMarshaller; use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; @@ -115,22 +114,39 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune protected function doInvalidate(array $tagIds): bool { foreach ($tagIds as $tagId) { - $tagsFolder = $this->getTagFolder($tagId); - if (!file_exists($tagsFolder)) { + if (!file_exists($tagsFolder = $this->getTagFolder($tagId))) { continue; } - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) { - if (!$itemLink->isLink()) { - throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink); + set_error_handler(static function () {}); + + try { + if (rename($tagsFolder, $renamed = substr_replace($tagsFolder, bin2hex(random_bytes(4)), -1))) { + $tagsFolder = $renamed.\DIRECTORY_SEPARATOR; + } else { + $renamed = null; } - $valueFile = $itemLink->getRealPath(); - if ($valueFile && file_exists($valueFile)) { - @unlink($valueFile); + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $itemLink) { + unlink(realpath($itemLink) ?: $itemLink); + unlink($itemLink); } - @unlink((string) $itemLink); + if (null === $renamed) { + continue; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + for ($j = 0; $j < 38; ++$j) { + rmdir($tagsFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]); + } + rmdir($tagsFolder.$chars[$i]); + } + rmdir($renamed); + } finally { + restore_error_handler(); } } From 20fd92571e4002449967563122dbe98415da4381 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 15:27:34 +0200 Subject: [PATCH 23/26] [Cache] cs fix --- .../Cache/Adapter/FilesystemTagAwareAdapter.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php index 23f507bfde..67801e8ab9 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php @@ -106,20 +106,20 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune protected function doInvalidate(array $tagIds): bool { foreach ($tagIds as $tagId) { - if (!file_exists($tagsFolder = $this->getTagFolder($tagId))) { + if (!file_exists($tagFolder = $this->getTagFolder($tagId))) { continue; } set_error_handler(static function () {}); try { - if (rename($tagsFolder, $renamed = substr_replace($tagsFolder, bin2hex(random_bytes(4)), -1))) { - $tagsFolder = $renamed.\DIRECTORY_SEPARATOR; + if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -1))) { + $tagFolder = $renamed.\DIRECTORY_SEPARATOR; } else { $renamed = null; } - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $itemLink) { + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagFolder, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $itemLink) { unlink(realpath($itemLink) ?: $itemLink); unlink($itemLink); } @@ -132,9 +132,9 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune for ($i = 0; $i < 38; ++$i) { for ($j = 0; $j < 38; ++$j) { - rmdir($tagsFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]); + rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]); } - rmdir($tagsFolder.$chars[$i]); + rmdir($tagFolder.$chars[$i]); } rmdir($renamed); } finally { From 0302b1d8b057777e13a375c1a5075b03947b0335 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 10:18:57 +0200 Subject: [PATCH 24/26] [Cache] improve perf of pruning for fs-based adapters --- .../Adapter/FilesystemTagAwareAdapter.php | 54 ++++++++++++++++++- .../Cache/Traits/FilesystemCommonTrait.php | 33 ++++++++++-- .../Cache/Traits/FilesystemTrait.php | 2 +- .../Component/Cache/Traits/PhpFilesTrait.php | 2 +- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php index 69548e0946..82c3960a84 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php @@ -25,6 +25,7 @@ use Symfony\Component\Cache\Traits\FilesystemTrait; class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface { use FilesystemTrait { + doClear as private doClearCache; doSave as private doSaveCache; doDelete as private doDeleteCache; } @@ -41,6 +42,55 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune $this->init($namespace, $directory); } + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + $ok = $this->doClearCache($namespace); + + if ('' !== $namespace) { + return $ok; + } + + set_error_handler(static function () {}); + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + try { + foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) { + if (rename($dir, $renamed = substr_replace($dir, bin2hex(random_bytes(4)), -8))) { + $dir = $renamed.\DIRECTORY_SEPARATOR; + } else { + $dir .= \DIRECTORY_SEPARATOR; + $renamed = null; + } + + for ($i = 0; $i < 38; ++$i) { + if (!file_exists($dir.$chars[$i])) { + continue; + } + for ($j = 0; $j < 38; ++$j) { + if (!file_exists($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + foreach (scandir($d, SCANDIR_SORT_NONE) ?: [] as $link) { + if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) { + unlink($d.\DIRECTORY_SEPARATOR.$link); + } + } + null === $renamed ?: rmdir($d); + } + null === $renamed ?: rmdir($dir.$chars[$i]); + } + null === $renamed ?: rmdir($renamed); + } + } finally { + restore_error_handler(); + } + + return $ok; + } + /** * {@inheritdoc} */ @@ -111,13 +161,13 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune set_error_handler(static function () {}); try { - if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -1))) { + if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -9))) { $tagFolder = $renamed.\DIRECTORY_SEPARATOR; } else { $renamed = null; } - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagFolder, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $itemLink) { + foreach ($this->scanHashDir($tagFolder) as $itemLink) { unlink(realpath($itemLink) ?: $itemLink); unlink($itemLink); } diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index 0e183ced99..d828982b82 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -26,7 +26,7 @@ trait FilesystemCommonTrait private function init(string $namespace, ?string $directory) { if (!isset($directory[0])) { - $directory = sys_get_temp_dir().'/symfony-cache'; + $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache'; } else { $directory = realpath($directory) ?: $directory; } @@ -55,12 +55,12 @@ trait FilesystemCommonTrait { $ok = true; - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) { + foreach ($this->scanHashDir($this->directory) as $file) { if ('' !== $namespace && 0 !== strpos($this->getFileKey($file), $namespace)) { continue; } - $ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok; + $ok = ($this->doUnlink($file) || !file_exists($file)) && $ok; } return $ok; @@ -123,6 +123,33 @@ trait FilesystemCommonTrait return ''; } + private function scanHashDir(string $directory): \Generator + { + if (!file_exists($directory)) { + return; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + if (!file_exists($directory.$chars[$i])) { + continue; + } + + for ($j = 0; $j < 38; ++$j) { + if (!file_exists($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + + foreach (@scandir($dir, SCANDIR_SORT_NONE) ?: [] as $file) { + if ('.' !== $file && '..' !== $file) { + yield $dir.\DIRECTORY_SEPARATOR.$file; + } + } + } + } + } + /** * @internal */ diff --git a/src/Symfony/Component/Cache/Traits/FilesystemTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemTrait.php index 31f0d74372..185eb0006d 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemTrait.php @@ -33,7 +33,7 @@ trait FilesystemTrait $time = time(); $pruned = true; - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + foreach ($this->scanHashDir($this->directory) as $file) { if (!$h = @fopen($file, 'rb')) { continue; } diff --git a/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php b/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php index baacefc152..41ff8bdd07 100644 --- a/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php +++ b/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php @@ -54,7 +54,7 @@ trait PhpFilesTrait set_error_handler($this->includeHandler); try { - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + foreach ($this->scanHashDir($this->directory) as $file) { try { if (\is_array($expiresAt = include $file)) { $expiresAt = $expiresAt[0]; From 31fcf93253168df12d325e95598656158722209f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 16:33:48 +0200 Subject: [PATCH 25/26] [Validator] sync NO and NB translations --- .../Resources/translations/validators.no.xlf | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index db534528d1..bfa9b1284e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -334,6 +334,38 @@ This value should be valid JSON. Verdien er ikke gyldig JSON. + + This collection should contain only unique elements. + Samlingen kan kun inneholde unike elementer. + + + This value should be positive. + Denne verdien må være positiv. + + + This value should be either positive or zero. + Denne verdien må være positiv eller null. + + + This value should be negative. + Denne verdien må være negativ. + + + This value should be either negative or zero. + Denne verdien må være negativ eller null. + + + This value is not a valid timezone. + Verdien er ikke en gyldig tidssone. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Dette passordet er lekket i et datainnbrudd, det må ikke tas i bruk. Vennligst bruk et annet passord. + + + This value should be between {{ min }} and {{ max }}. + Verdien må være mellom {{ min }} og {{ max }}. + From c216f7f268e0e47f907c41ade328de6912a56608 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Oct 2019 16:35:33 +0200 Subject: [PATCH 26/26] cs fix --- src/Symfony/Component/EventDispatcher/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/Symfony/Component/EventDispatcher/CHANGELOG.md index 2e5afbc6f5..54fd04227b 100644 --- a/src/Symfony/Component/EventDispatcher/CHANGELOG.md +++ b/src/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -4,8 +4,8 @@ CHANGELOG 4.4.0 ----- -* `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. -* Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. + * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. + * Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. 4.3.0 ----- @@ -16,7 +16,7 @@ CHANGELOG 4.1.0 ----- - * added support for invokable event listeners tagged with `kernel.event_listener` by default + * added support for invokable event listeners tagged with `kernel.event_listener` by default * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. * The `TraceableEventDispatcherInterface` has been deprecated.