diff --git a/UPGRADE-4.2.md b/UPGRADE-4.2.md
index c1bb03f5ae..8f7cc54411 100644
--- a/UPGRADE-4.2.md
+++ b/UPGRADE-4.2.md
@@ -192,15 +192,15 @@ HttpKernel
* The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been deprecated
* The `KernelInterface::getName()` and the `kernel.name` parameter have been deprecated
- * Deprecated the first and second constructor argument of `ConfigDataCollector`
- * Deprecated `ConfigDataCollector::getApplicationName()`
+ * Deprecated the first and second constructor argument of `ConfigDataCollector`
+ * Deprecated `ConfigDataCollector::getApplicationName()`
* Deprecated `ConfigDataCollector::getApplicationVersion()`
Messenger
---------
* The `MiddlewareInterface::handle()` and `SenderInterface::send()` methods must now return an `Envelope` instance.
- * The return value of handlers isn't forwarded anymore by middleware and buses.
+ * The return value of handlers isn't forwarded anymore by middleware and buses.
If you used to return a value, e.g in query bus handlers, you can either:
- get the result from the `HandledStamp` in the envelope returned by the bus.
- use the `HandleTrait` to leverage a message bus, expecting a single, synchronous message handling and returning its result.
@@ -214,15 +214,15 @@ Messenger
$query->setResult($yourResult);
```
* The `EnvelopeAwareInterface` was removed and the `MiddlewareInterface::handle()` method now requires an `Envelope` object
- as first argument. When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
- If you use your own `MessageBusInterface` implementation, you must wrap the message in an `Envelope` before passing it to middleware.
+ as first argument. When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
+ If you use your own `MessageBusInterface` implementation, you must wrap the message in an `Envelope` before passing it to middleware.
If you created your own middleware, you must change the signature to always expect an `Envelope`.
* The `MiddlewareInterface::handle()` second argument (`callable $next`) has changed in favor of a `StackInterface` instance.
- When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
- If you use your own `MessageBusInterface` implementation, you can use the `StackMiddleware` implementation.
+ When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
+ If you use your own `MessageBusInterface` implementation, you can use the `StackMiddleware` implementation.
If you created your own middleware, you must change the signature to always expect an `StackInterface` instance
and call `$stack->next()->handle($envelope, $stack)` instead of `$next` to call the next middleware:
-
+
Before:
```php
public function handle($message, callable $next): Envelope
@@ -230,7 +230,7 @@ Messenger
// do something before
$message = $next($message);
// do something after
-
+
return $message;
}
```
@@ -242,7 +242,7 @@ Messenger
// do something before
$envelope = $stack->next()->handle($envelope, $stack);
// do something after
-
+
return $envelope;
}
```
@@ -251,7 +251,7 @@ Messenger
respectively `ReceivedStamp`, `ValidationStamp`, `SerializerStamp` and moved to the `Stamp` namespace.
* `AllowNoHandlerMiddleware` has been removed in favor of a new constructor argument on `HandleMessageMiddleware`
* The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface`
- as first constructor argument, i.e a message bus locator. The CLI command now expects a mandatory
+ as first constructor argument, i.e a message bus locator. The CLI command now expects a mandatory
`--bus` option value if there is more than one bus in the locator.
* `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item
needs to be an associative array or the method name.
diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
index 8ac4a79beb..dac9a897ee 100644
--- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
+++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
@@ -106,7 +106,7 @@ $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar')
|| ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar 2> /dev/null`))
|| ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer`) : `which composer 2> /dev/null`))
|| file_exists($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? `git rev-parse --show-toplevel 2> NUL` : `git rev-parse --show-toplevel 2> /dev/null`).DIRECTORY_SEPARATOR.'composer.phar')
- ? $PHP.' '.escapeshellarg($COMPOSER)
+ ? (file_get_contents($COMPOSER, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang
: 'composer';
$SYMFONY_PHPUNIT_REMOVE = $getEnvVar('SYMFONY_PHPUNIT_REMOVE', 'phpspec/prophecy'.($PHPUNIT_VERSION < 6.0 ? ' symfony/yaml': ''));
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
index a97a38e520..45843e713f 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
@@ -65,12 +65,14 @@
{%- endif -%}
{%- if preferred_choices|length > 0 -%}
{% set options = preferred_choices %}
+ {% set render_preferred_choices = true %}
{{- block('choice_widget_options') -}}
{%- if choices|length > 0 and separator is not none -%}
{%- endif -%}
{%- endif -%}
{%- set options = choices -%}
+ {%- set render_preferred_choices = false -%}
{{- block('choice_widget_options') -}}
{%- endblock choice_widget_collapsed -%}
@@ -83,7 +85,7 @@
{{- block('choice_widget_options') -}}
{%- else -%}
-
+
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
@@ -226,13 +228,11 @@
'%name%': name,
'%id%': id,
}) %}
- {%- elseif label is same as(false) -%}
- {% set translation_domain = false %}
- {%- else -%}
+ {%- elseif label is not same as(false) -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
-
+
{%- endblock button_widget -%}
{%- block submit_widget -%}
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig
index 8ab44ccc77..b02b94210d 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig
@@ -160,12 +160,14 @@
{%- endif %}
{%- if preferred_choices|length > 0 -%}
{% set options = preferred_choices %}
+ {% set render_preferred_choices = true %}
{{- block('choice_widget_options') -}}
{% if choices|length > 0 and separator is not none -%}
{%- endif %}
{%- endif -%}
{% set options = choices -%}
+ {%- set render_preferred_choices = false -%}
{{- block('choice_widget_options') -}}
{%- endblock choice_widget_collapsed %}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
index ff5c677c19..8504f8b7c0 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
@@ -546,6 +546,31 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
);
}
+ public function testSingleChoiceWithSelectedPreferred()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
+ 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
+ 'preferred_choices' => ['&a'],
+ 'multiple' => false,
+ 'expanded' => false,
+ ]);
+
+ $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --', 'attr' => ['class' => 'my&class']],
+'/select
+ [@name="name"]
+ [@class="my&class form-control"]
+ [not(@required)]
+ [
+ ./option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
+ /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
+ /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
+ /following-sibling::option[@value="&b"][.="[trans]Choice&B[/trans]"]
+ ]
+ [count(./option)=4]
+'
+ );
+ }
+
public function testSingleChoiceWithPreferredAndNoSeparator()
{
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
index 5e6277567e..290f1da5e3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
@@ -102,11 +102,12 @@ final class ContainerLintCommand extends Command
$refl->setAccessible(true);
$refl->setValue($parameterBag, true);
- $passConfig = $container->getCompilerPassConfig();
- $passConfig->setRemovingPasses([]);
- $passConfig->setAfterRemovingPasses([]);
-
- $skippedIds = $kernelContainer->getRemovedIds();
+ $skippedIds = [];
+ foreach ($container->getServiceIds() as $serviceId) {
+ if (0 === strpos($serviceId, '.errored.')) {
+ $skippedIds[$serviceId] = true;
+ }
+ }
}
$container->setParameter('container.build_hash', 'lint_container');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
index e717b07389..f578c2d246 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
@@ -175,12 +175,12 @@ EOF
}
}
- $errorIo->title('Translation Messages Extractor and Dumper');
- $errorIo->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName));
+ $io->title('Translation Messages Extractor and Dumper');
+ $io->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName));
// load any messages from templates
$extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
- $errorIo->comment('Parsing templates...');
+ $io->comment('Parsing templates...');
$this->extractor->setPrefix($input->getOption('prefix'));
foreach ($viewsPaths as $path) {
if (is_dir($path) || is_file($path)) {
@@ -190,7 +190,7 @@ EOF
// load any existing messages from the translation files
$currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
- $errorIo->comment('Loading translation files...');
+ $io->comment('Loading translation files...');
foreach ($transPaths as $path) {
if (is_dir($path)) {
$this->reader->read($path, $currentCatalogue);
@@ -258,7 +258,7 @@ EOF
}
if ('xlf' === $input->getOption('output-format')) {
- $errorIo->comment(sprintf('Xliff output version is %s', $input->getOption('xliff-version')));
+ $io->comment(sprintf('Xliff output version is %s', $input->getOption('xliff-version')));
}
$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
@@ -270,7 +270,7 @@ EOF
// save the files
if (true === $input->getOption('force')) {
- $errorIo->comment('Writing files...');
+ $io->comment('Writing files...');
$bundleTransPath = false;
foreach ($transPaths as $path) {
@@ -290,7 +290,7 @@ EOF
}
}
- $errorIo->success($resultMessage.'.');
+ $io->success($resultMessage.'.');
return 0;
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php
index 3a1046b0c4..51f56c220d 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php
@@ -33,7 +33,7 @@ class ClearRememberMeTest extends AbstractWebTestCase
$this->assertNotNull($cookieJar->get('REMEMBERME'));
$client->request('GET', '/foo');
- $this->assertSame(200, $client->getResponse()->getStatusCode());
+ $this->assertRedirect($client->getResponse(), '/login');
$this->assertNull($cookieJar->get('REMEMBERME'));
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index 21cc505551..6465faa6e0 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -24,7 +24,7 @@
"symfony/security-core": "^4.4|^5.0",
"symfony/security-csrf": "^4.4|^5.0",
"symfony/security-guard": "^4.4|^5.0",
- "symfony/security-http": "^4.4.1|^5.0.1"
+ "symfony/security-http": "^4.4.3|^5.0.3"
},
"require-dev": {
"doctrine/doctrine-bundle": "^2.0",
diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
index e082df1c45..f52d0271e4 100644
--- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
+++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
@@ -103,7 +103,12 @@ class CachePoolPass implements CompilerPassInterface
if (ChainAdapter::class === $class) {
$adapters = [];
foreach ($adapter->getArgument(0) as $provider => $adapter) {
- $chainedPool = $adapter = new ChildDefinition($adapter);
+ if ($adapter instanceof ChildDefinition) {
+ $chainedPool = $adapter;
+ } else {
+ $chainedPool = $adapter = new ChildDefinition($adapter);
+ }
+
$chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
$chainedClass = '';
diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
index e763dabe48..20701adcb4 100644
--- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
+++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
@@ -12,7 +12,9 @@
namespace Symfony\Component\Cache\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
+use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -174,4 +176,42 @@ class CachePoolPassTest extends TestCase
$this->cachePoolPass->process($container);
}
+
+ public function testChainAdapterPool()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.container_class', 'app');
+ $container->setParameter('kernel.project_dir', 'foo');
+
+ $container->register('cache.adapter.array', ArrayAdapter::class)
+ ->addTag('cache.pool');
+ $container->register('cache.adapter.apcu', ApcuAdapter::class)
+ ->setArguments([null, 0, null])
+ ->addTag('cache.pool');
+ $container->register('cache.chain', ChainAdapter::class)
+ ->addArgument(['cache.adapter.array', 'cache.adapter.apcu'])
+ ->addTag('cache.pool');
+ $container->setDefinition('cache.app', new ChildDefinition('cache.chain'))
+ ->addTag('cache.pool');
+ $container->setDefinition('doctrine.result_cache_pool', new ChildDefinition('cache.app'))
+ ->addTag('cache.pool');
+
+ $this->cachePoolPass->process($container);
+
+ $appCachePool = $container->getDefinition('cache.app');
+ $this->assertInstanceOf(ChildDefinition::class, $appCachePool);
+ $this->assertSame('cache.chain', $appCachePool->getParent());
+
+ $chainCachePool = $container->getDefinition('cache.chain');
+ $this->assertNotInstanceOf(ChildDefinition::class, $chainCachePool);
+ $this->assertCount(2, $chainCachePool->getArgument(0));
+ $this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[0]);
+ $this->assertSame('cache.adapter.array', $chainCachePool->getArgument(0)[0]->getParent());
+ $this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[1]);
+ $this->assertSame('cache.adapter.apcu', $chainCachePool->getArgument(0)[1]->getParent());
+
+ $doctrineCachePool = $container->getDefinition('doctrine.result_cache_pool');
+ $this->assertInstanceOf(ChildDefinition::class, $doctrineCachePool);
+ $this->assertSame('cache.app', $doctrineCachePool->getParent());
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
index 4bbcedbf12..7c414258b7 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
+use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
@@ -219,6 +220,10 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
return;
}
+ if (\in_array($type, ['callable', 'Closure'], true) && $value instanceof ServiceClosureArgument) {
+ return;
+ }
+
if ('iterable' === $type && (\is_array($value) || $value instanceof \Traversable || $value instanceof IteratorArgument)) {
return;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
index 22a29fa4d6..350f85296a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
+use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -697,4 +698,28 @@ class CheckTypeDeclarationsPassTest extends TestCase
$this->addToAssertionCount(1);
}
+
+ public function testProcessSuccessWhenPassingServiceClosureArgumentToCallable()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register('bar', BarMethodCall::class)
+ ->addMethodCall('setCallable', [new ServiceClosureArgument(new Reference('foo'))]);
+
+ (new CheckTypeDeclarationsPass(true))->process($container);
+
+ $this->addToAssertionCount(1);
+ }
+
+ public function testProcessSuccessWhenPassingServiceClosureArgumentToClosure()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register('bar', BarMethodCall::class)
+ ->addMethodCall('setClosure', [new ServiceClosureArgument(new Reference('foo'))]);
+
+ (new CheckTypeDeclarationsPass(true))->process($container);
+
+ $this->addToAssertionCount(1);
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php
index b705601609..69f1a693a4 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php
@@ -40,4 +40,8 @@ class BarMethodCall
public function setCallable(callable $callable): void
{
}
+
+ public function setClosure(\Closure $closure): void
+ {
+ }
}
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index eb17855427..8851514451 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -272,7 +272,10 @@ final class Dotenv
$this->cursor += 1 + $len;
} elseif ('"' === $this->data[$this->cursor]) {
$value = '';
- ++$this->cursor;
+
+ if (++$this->cursor === $this->end) {
+ throw $this->createFormatException('Missing quote to end the value');
+ }
while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) {
$value .= $this->data[$this->cursor];
diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
index 3f854cbd72..1ae3eefa94 100644
--- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
@@ -40,6 +40,7 @@ class DotenvTest extends TestCase
['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"],
['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"],
['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"],
+ ["FOO=\"foo\nBAR=\"bar\"", "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo\\nBAR=\"bar\"...\n ^ line 1 offset 18"],
['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"],
['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"],
['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"],
diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php
index 3098200b01..1e09afbb9f 100644
--- a/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php
+++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php
@@ -30,6 +30,10 @@ class ClassNotFoundErrorEnhancerTest extends TestCase
// get class loaders wrapped by DebugClassLoader
if ($function[0] instanceof DebugClassLoader) {
$function = $function[0]->getClassLoader();
+
+ if (!\is_array($function)) {
+ continue;
+ }
}
if ($function[0] instanceof ComposerClassLoader) {
diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php
index e756ea5d3f..08023b9c42 100644
--- a/src/Symfony/Component/HttpClient/HttplugClient.php
+++ b/src/Symfony/Component/HttpClient/HttplugClient.php
@@ -16,6 +16,7 @@ use Http\Client\Exception\NetworkException;
use Http\Client\Exception\RequestException;
use Http\Client\HttpAsyncClient;
use Http\Client\HttpClient as HttplugInterface;
+use Http\Discovery\Exception\NotFoundException;
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Message\RequestFactory;
use Http\Message\StreamFactory;
@@ -75,9 +76,13 @@ final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestF
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".');
}
- $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
- $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
- $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
+ try {
+ $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
+ $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
+ $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
+ } catch (NotFoundException $e) {
+ throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e);
+ }
}
$this->waitLoop = new HttplugWaitLoop($this->client, $this->promisePool, $this->responseFactory, $this->streamFactory);
diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php
index ba59dc11f7..67c2fdb8f0 100644
--- a/src/Symfony/Component/HttpClient/Psr18Client.php
+++ b/src/Symfony/Component/HttpClient/Psr18Client.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\HttpClient;
+use Http\Discovery\Exception\NotFoundException;
use Http\Discovery\Psr17FactoryDiscovery;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\Request;
@@ -68,9 +69,13 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".');
}
- $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
- $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
- $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
+ try {
+ $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
+ $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
+ $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
+ } catch (NotFoundException $e) {
+ throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e);
+ }
}
/**
diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
index 1222a4b1e9..158bcef04e 100644
--- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
+++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
@@ -353,7 +353,7 @@ trait ResponseTrait
}
if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) {
- $multi->handlesActivity[$j] = [null, new TransportException('Failed writing %d bytes to the response buffer.', \strlen($chunk))];
+ $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))];
continue;
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 4e6770e4ec..ff23192a54 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -475,7 +475,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
}
}
- public function __destruct()
+ public function release()
{
flock($this->lock, LOCK_UN);
fclose($this->lock);
@@ -553,7 +553,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
}
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
- unset($cache);
+ $cache->release();
$this->container = require $cachePath;
$this->container->set('kernel', $this);
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
index 57eafa2c1d..0be034dd3d 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
@@ -186,6 +186,18 @@ class ConnectionTest extends TestCase
$redis->del('messenger-getnonblocking');
}
+ public function testJsonError()
+ {
+ $redis = new \Redis();
+ $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis);
+ try {
+ $connection->add("\xB1\x31", []);
+ } catch (TransportException $e) {
+ }
+
+ $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage());
+ }
+
public function testMaxEntries()
{
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
index 33d6057f67..e198022162 100644
--- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
@@ -248,6 +248,10 @@ class Connection
'uniqid' => uniqid('', true),
]);
+ if (false === $message) {
+ throw new TransportException(json_last_error_msg());
+ }
+
$score = (int) ($this->getCurrentTimeInMilliseconds() + $delayInMs);
$added = $this->connection->zadd($this->queue, ['NX'], $score, $message);
} else {
@@ -256,6 +260,10 @@ class Connection
'headers' => $headers,
]);
+ if (false === $message) {
+ throw new TransportException(json_last_error_msg());
+ }
+
if ($this->maxEntries) {
$added = $this->connection->xadd($this->stream, '*', ['message' => $message], $this->maxEntries, true);
} else {
diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php
index b9c984f21d..3846455e44 100644
--- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php
+++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php
@@ -45,7 +45,7 @@ class GuardAuthenticationListener extends AbstractListener
* @param string $providerKey The provider (i.e. firewall) key
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
*/
- public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, $guardAuthenticators, LoggerInterface $logger = null)
+ public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, iterable $guardAuthenticators, LoggerInterface $logger = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php
index 49eb947872..99704b3e75 100644
--- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php
+++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php
@@ -48,7 +48,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
* @param string $providerKey The provider (i.e. firewall) key
*/
- public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordEncoderInterface $passwordEncoder = null)
+ public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordEncoderInterface $passwordEncoder = null)
{
$this->guardAuthenticators = $guardAuthenticators;
$this->userProvider = $userProvider;
diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
index 487f864e9b..55fd885918 100644
--- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
+++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
@@ -94,6 +94,10 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
*/
final public function autoLogin(Request $request): ?TokenInterface
{
+ if (($cookie = $request->attributes->get(self::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) {
+ return null;
+ }
+
if (null === $cookie = $request->cookies->get($this->options['name'])) {
return null;
}
diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php
index c476e65403..7a0506dfe8 100644
--- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php
@@ -39,6 +39,17 @@ class AbstractRememberMeServicesTest extends TestCase
$this->assertNull($service->autoLogin(new Request()));
}
+ public function testAutoLoginReturnsNullAfterLoginFail()
+ {
+ $service = $this->getService(null, ['name' => 'foo', 'path' => null, 'domain' => null]);
+
+ $request = new Request();
+ $request->cookies->set('foo', 'foo');
+
+ $service->loginFail($request);
+ $this->assertNull($service->autoLogin($request));
+ }
+
public function testAutoLoginThrowsExceptionWhenImplementationDoesNotReturnUserInterface()
{
$this->expectException('RuntimeException');
diff --git a/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php b/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php
index 80840a042f..7ce17cc399 100644
--- a/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php
+++ b/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php
@@ -47,7 +47,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
return $this->normalizeFallback($propertyName, $class, $format, $context);
}
- if (!isset(self::$normalizeCache[$class][$propertyName])) {
+ if (!\array_key_exists($class, self::$normalizeCache) || !\array_key_exists($propertyName, self::$normalizeCache[$class])) {
self::$normalizeCache[$class][$propertyName] = $this->getCacheValueForNormalization($propertyName, $class);
}
@@ -64,7 +64,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
}
$cacheKey = $this->getCacheKey($class, $context);
- if (!isset(self::$denormalizeCache[$cacheKey][$propertyName])) {
+ if (!\array_key_exists($cacheKey, self::$denormalizeCache) || !\array_key_exists($propertyName, self::$denormalizeCache[$cacheKey])) {
self::$denormalizeCache[$cacheKey][$propertyName] = $this->getCacheValueForDenormalization($propertyName, $class, $context);
}
@@ -78,7 +78,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
}
$attributesMetadata = $this->metadataFactory->getMetadataFor($class)->getAttributesMetadata();
- if (!isset($attributesMetadata[$propertyName])) {
+ if (!\array_key_exists($propertyName, $attributesMetadata)) {
return null;
}
@@ -93,7 +93,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
private function getCacheValueForDenormalization(string $propertyName, string $class, array $context): ?string
{
$cacheKey = $this->getCacheKey($class, $context);
- if (!isset(self::$attributesMetadataCache[$cacheKey])) {
+ if (!\array_key_exists($cacheKey, self::$attributesMetadataCache)) {
self::$attributesMetadataCache[$cacheKey] = $this->getCacheValueForAttributesMetadata($class, $context);
}