>', self::$bgColor[$clientId % 8]);
+ $output->write($logBlock);
+
+ $this->handler->handle($record);
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
index 1a2518812f..d1d5f6d8a4 100644
--- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
+++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
@@ -21,6 +21,7 @@ class TaggedIteratorArgument extends IteratorArgument
private $tag;
private $indexAttribute;
private $defaultIndexMethod;
+ private $defaultPriorityMethod;
private $needsIndexes = false;
/**
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
index 2147d53f12..ccd11e9d48 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
@@ -152,6 +152,10 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
return;
}
+ if ('object' === $type) {
+ return;
+ }
+
if (is_a($class, $type, true)) {
return;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
index 51bc7c6779..b012a65625 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php
@@ -15,12 +15,14 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Bar;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgument;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgumentNotNull;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\FooObject;
/**
* @author Nicolas Grekas
@@ -390,6 +392,21 @@ class CheckTypeDeclarationsPassTest extends TestCase
$this->addToAssertionCount(1);
}
+ /**
+ * @requires PHP 7.2
+ */
+ public function testProcessSuccessWhenPassingDefinitionForObjectType()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register('foo_object', FooObject::class)
+ ->addArgument(new Definition(Foo::class));
+
+ (new CheckTypeDeclarationsPass(true))->process($container);
+
+ $this->addToAssertionCount(1);
+ }
+
public function testProcessFactory()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/FooObject.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/FooObject.php
new file mode 100644
index 0000000000..44cfaf0d0a
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/FooObject.php
@@ -0,0 +1,10 @@
+createFormatException(sprintf('Unsupported character "%s" found in the default value of variable "$%s".', $unsupportedChars[0], $name));
diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
index ed54d2a689..489c7fa6d1 100644
--- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
@@ -172,6 +172,7 @@ class DotenvTest extends TestCase
["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}']],
+ ["FOO=foo\nFOOBAR=\${FOO}\${BAR}", ['FOO' => 'foo', 'FOOBAR' => 'foo']],
];
if ('\\' !== \DIRECTORY_SEPARATOR) {
diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
index bb1484ab67..d4299da4d9 100644
--- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
+++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -783,7 +783,7 @@ class FilesystemTest extends FilesystemTestCase
$file = $this->workspace.\DIRECTORY_SEPARATOR.'file';
$link = $this->workspace.\DIRECTORY_SEPARATOR.'link';
- // $file does not exists right now: creating "broken" links is a wanted feature
+ // $file does not exist right now: creating "broken" links is a wanted feature
$this->filesystem->symlink($file, $link);
$this->assertTrue(is_link($link));
diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php
index 5e9fe4221b..0f872dfa97 100644
--- a/src/Symfony/Component/HttpClient/CurlHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php
@@ -23,6 +23,7 @@ use Symfony\Component\HttpClient\Response\ResponseStream;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
+use Symfony\Contracts\Service\ResetInterface;
/**
* A performant implementation of the HttpClientInterface contracts based on the curl extension.
@@ -32,7 +33,7 @@ use Symfony\Contracts\HttpClient\ResponseStreamInterface;
*
* @author Nicolas Grekas
*/
-final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
+final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface
{
use HttpClientTrait;
use LoggerAwareTrait;
@@ -324,9 +325,17 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
return new ResponseStream(CurlResponse::stream($responses, $timeout));
}
- public function __destruct()
+ public function reset()
{
+ if ($this->logger) {
+ foreach ($this->multi->pushedResponses as $url => $response) {
+ $this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
+ }
+ }
+
$this->multi->pushedResponses = [];
+ $this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals;
+ $this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = [];
if (\is_resource($this->multi->handle)) {
if (\defined('CURLMOPT_PUSHFUNCTION')) {
@@ -344,6 +353,11 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
}
}
+ public function __destruct()
+ {
+ $this->reset();
+ }
+
private static function handlePush($parent, $pushed, array $requestHeaders, CurlClientState $multi, int $maxPendingPushes, ?LoggerInterface $logger): int
{
$headers = [];
@@ -363,12 +377,6 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
$url = $headers[':scheme'][0].'://'.$headers[':authority'][0];
- if ($maxPendingPushes <= \count($multi->pushedResponses)) {
- $logger && $logger->debug(sprintf('Rejecting pushed response from "%s" for "%s": the queue is full', $origin, $url));
-
- return CURL_PUSH_DENY;
- }
-
// curl before 7.65 doesn't validate the pushed ":authority" header,
// but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host,
// ignoring domains mentioned as alt-name in the certificate for now (same as curl).
@@ -378,6 +386,12 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
return CURL_PUSH_DENY;
}
+ if ($maxPendingPushes <= \count($multi->pushedResponses)) {
+ $fifoUrl = key($multi->pushedResponses);
+ unset($multi->pushedResponses[$fifoUrl]);
+ $logger && $logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl));
+ }
+
$url .= $headers[':path'][0];
$logger && $logger->debug(sprintf('Queueing pushed response: "%s"', $url));
diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
index 948b2d8eae..fb9228b106 100644
--- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
+++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
@@ -15,11 +15,12 @@ use Symfony\Component\HttpClient\TraceableHttpClient;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
/**
* @author Jérémy Romey
*/
-final class HttpClientDataCollector extends DataCollector
+final class HttpClientDataCollector extends DataCollector implements LateDataCollectorInterface
{
/**
* @var TraceableHttpClient[]
@@ -36,7 +37,7 @@ final class HttpClientDataCollector extends DataCollector
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
- $this->initData();
+ $this->reset();
foreach ($this->clients as $name => $client) {
[$errorCount, $traces] = $this->collectOnClient($client);
@@ -51,6 +52,13 @@ final class HttpClientDataCollector extends DataCollector
}
}
+ public function lateCollect()
+ {
+ foreach ($this->clients as $client) {
+ $client->reset();
+ }
+ }
+
public function getClients(): array
{
return $this->data['clients'] ?? [];
@@ -66,17 +74,6 @@ final class HttpClientDataCollector extends DataCollector
return $this->data['error_count'] ?? 0;
}
- /**
- * {@inheritdoc}
- */
- public function reset()
- {
- $this->initData();
- foreach ($this->clients as $client) {
- $client->reset();
- }
- }
-
/**
* {@inheritdoc}
*/
@@ -85,7 +82,7 @@ final class HttpClientDataCollector extends DataCollector
return 'http_client';
}
- private function initData()
+ public function reset()
{
$this->data = [
'clients' => [],
diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
index e06f9a58ba..6188587288 100644
--- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
@@ -228,15 +228,7 @@ final class CurlResponse implements ResponseInterface
} finally {
$this->close();
- // Clear local caches when the only remaining handles are about pushed responses
if (!$this->multi->openHandles) {
- if ($this->logger) {
- foreach ($this->multi->pushedResponses as $url => $response) {
- $this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
- }
- }
-
- $this->multi->pushedResponses = [];
// Schedule DNS cache eviction for the next request
$this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals;
$this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = [];
diff --git a/src/Symfony/Component/HttpClient/ScopingHttpClient.php b/src/Symfony/Component/HttpClient/ScopingHttpClient.php
index 3f071720f0..a55d011953 100644
--- a/src/Symfony/Component/HttpClient/ScopingHttpClient.php
+++ b/src/Symfony/Component/HttpClient/ScopingHttpClient.php
@@ -15,13 +15,14 @@ use Symfony\Component\HttpClient\Exception\InvalidArgumentException;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
+use Symfony\Contracts\Service\ResetInterface;
/**
* Auto-configure the default options based on the requested URL.
*
* @author Anthony Martin
*/
-class ScopingHttpClient implements HttpClientInterface
+class ScopingHttpClient implements HttpClientInterface, ResetInterface
{
use HttpClientTrait;
@@ -90,4 +91,11 @@ class ScopingHttpClient implements HttpClientInterface
{
return $this->client->stream($responses, $timeout);
}
+
+ public function reset()
+ {
+ if ($this->client instanceof ResetInterface) {
+ $this->client->reset();
+ }
+ }
}
diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php
index 4fd367fd9d..7aedba1523 100644
--- a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php
@@ -13,13 +13,23 @@ namespace Symfony\Component\HttpClient\Tests;
use Psr\Log\AbstractLogger;
use Symfony\Component\HttpClient\CurlHttpClient;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Symfony\Component\Process\Process;
use Symfony\Contracts\HttpClient\HttpClientInterface;
+/*
+Tests for HTTP2 Push need a recent version of both PHP and curl. This docker command should run them:
+docker run -it --rm -v $(pwd):/app -v /path/to/vulcain:/usr/local/bin/vulcain -w /app php:7.3-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push
+The vulcain binary can be found at https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz - see https://github.com/dunglas/vulcain for source
+*/
+
/**
* @requires extension curl
*/
class CurlHttpClientTest extends HttpClientTestCase
{
+ private static $vulcainStarted = false;
+
protected function getHttpClient(string $testCase): HttpClientInterface
{
return new CurlHttpClient();
@@ -28,7 +38,81 @@ class CurlHttpClientTest extends HttpClientTestCase
/**
* @requires PHP 7.2.17
*/
- public function testHttp2Push()
+ public function testHttp2PushVulcain()
+ {
+ $client = $this->getVulcainClient();
+ $logger = new TestLogger();
+ $client->setLogger($logger);
+
+ $responseAsArray = $client->request('GET', 'https://127.0.0.1:3000/json', [
+ 'headers' => [
+ 'Preload' => '/documents/*/id',
+ ],
+ ])->toArray();
+
+ foreach ($responseAsArray['documents'] as $document) {
+ $client->request('GET', 'https://127.0.0.1:3000'.$document['id'])->toArray();
+ }
+
+ $client->reset();
+
+ $expected = [
+ 'Request: "GET https://127.0.0.1:3000/json"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/1"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/2"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/3"',
+ 'Response: "200 https://127.0.0.1:3000/json"',
+ 'Accepting pushed response: "GET https://127.0.0.1:3000/json/1"',
+ 'Response: "200 https://127.0.0.1:3000/json/1"',
+ 'Accepting pushed response: "GET https://127.0.0.1:3000/json/2"',
+ 'Response: "200 https://127.0.0.1:3000/json/2"',
+ 'Accepting pushed response: "GET https://127.0.0.1:3000/json/3"',
+ 'Response: "200 https://127.0.0.1:3000/json/3"',
+ ];
+ $this->assertSame($expected, $logger->logs);
+ }
+
+ /**
+ * @requires PHP 7.2.17
+ */
+ public function testHttp2PushVulcainWithUnusedResponse()
+ {
+ $client = $this->getVulcainClient();
+ $logger = new TestLogger();
+ $client->setLogger($logger);
+
+ $responseAsArray = $client->request('GET', 'https://127.0.0.1:3000/json', [
+ 'headers' => [
+ 'Preload' => '/documents/*/id',
+ ],
+ ])->toArray();
+
+ $i = 0;
+ foreach ($responseAsArray['documents'] as $document) {
+ $client->request('GET', 'https://127.0.0.1:3000'.$document['id'])->toArray();
+ if (++$i >= 2) {
+ break;
+ }
+ }
+
+ $client->reset();
+
+ $expected = [
+ 'Request: "GET https://127.0.0.1:3000/json"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/1"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/2"',
+ 'Queueing pushed response: "https://127.0.0.1:3000/json/3"',
+ 'Response: "200 https://127.0.0.1:3000/json"',
+ 'Accepting pushed response: "GET https://127.0.0.1:3000/json/1"',
+ 'Response: "200 https://127.0.0.1:3000/json/1"',
+ 'Accepting pushed response: "GET https://127.0.0.1:3000/json/2"',
+ 'Response: "200 https://127.0.0.1:3000/json/2"',
+ 'Unused pushed response: "https://127.0.0.1:3000/json/3"',
+ ];
+ $this->assertSame($expected, $logger->logs);
+ }
+
+ private function getVulcainClient(): CurlHttpClient
{
if (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304) {
$this->markTestSkipped('PHP 7.3.0 to 7.3.3 don\'t support HTTP/2 PUSH');
@@ -38,32 +122,44 @@ class CurlHttpClientTest extends HttpClientTestCase
$this->markTestSkipped('curl <7.61 is used or it is not compiled with support for HTTP/2 PUSH');
}
- $logger = new class() extends AbstractLogger {
- public $logs = [];
+ $client = new CurlHttpClient(['verify_peer' => false, 'verify_host' => false]);
- public function log($level, $message, array $context = []): void
- {
- $this->logs[] = $message;
- }
- };
+ if (static::$vulcainStarted) {
+ return $client;
+ }
- $client = new CurlHttpClient([], 6, 2);
- $client->setLogger($logger);
+ if (200 !== $client->request('GET', 'http://127.0.0.1:8057/json')->getStatusCode()) {
+ $this->markTestSkipped('symfony/http-client-contracts >= 2.0.1 required');
+ }
- $index = $client->request('GET', 'https://http2.akamai.com/');
- $index->getContent();
+ $process = new Process(['vulcain'], null, [
+ 'DEBUG' => 1,
+ 'UPSTREAM' => 'http://127.0.0.1:8057',
+ 'ADDR' => ':3000',
+ 'KEY_FILE' => __DIR__.'/Fixtures/tls/server.key',
+ 'CERT_FILE' => __DIR__.'/Fixtures/tls/server.crt',
+ ]);
+ $process->start();
- $css = $client->request('GET', 'https://http2.akamai.com/resources/push.css');
+ register_shutdown_function([$process, 'stop']);
+ sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1);
- $css->getHeaders();
+ if (!$process->isRunning()) {
+ throw new ProcessFailedException($process);
+ }
- $expected = [
- 'Request: "GET https://http2.akamai.com/"',
- 'Queueing pushed response: "https://http2.akamai.com/resources/push.css"',
- 'Response: "200 https://http2.akamai.com/"',
- 'Accepting pushed response: "GET https://http2.akamai.com/resources/push.css"',
- 'Response: "200 https://http2.akamai.com/resources/push.css"',
- ];
- $this->assertSame($expected, $logger->logs);
+ static::$vulcainStarted = true;
+
+ return $client;
+ }
+}
+
+class TestLogger extends AbstractLogger
+{
+ public $logs = [];
+
+ public function log($level, $message, array $context = []): void
+ {
+ $this->logs[] = $message;
}
}
diff --git a/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.crt b/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.crt
new file mode 100644
index 0000000000..3903667223
--- /dev/null
+++ b/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiYCCQDpVvfmCZt2GzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
+UzEUMBIGA1UEBwwLR290aGFtIENpdHkxEjAQBgNVBAMMCWxvY2FsaG9zdDEoMCYG
+CSqGSIb3DQEJARYZZHVuZ2xhcyttZXJjdXJlQGdtYWlsLmNvbTAeFw0xOTAxMjMx
+NTUzMzlaFw0yOTAxMjAxNTUzMzlaMGExCzAJBgNVBAYTAlVTMRQwEgYDVQQHDAtH
+b3RoYW0gQ2l0eTESMBAGA1UEAwwJbG9jYWxob3N0MSgwJgYJKoZIhvcNAQkBFhlk
+dW5nbGFzK21lcmN1cmVAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuKnXkBSJwOwkKfR58wP/yLYW9QFX2THoqN8iffangRmZwc5KLE6F
+1S8jYMv3JGiJ95Ij3MezAfuBCdgPqqP8JrR1XwjR1RFZMOL/4U9R9OuMVng04PLw
+L6TzKoEtZuExHUWFP0+5AYblgno2hoN/HVuox8m6zQrBNcbhTgDIjP5Hn491d9od
+MtS3OxksDLr1UIOUGUWF7MQMN7lsN7rgT5qxoCkcAGAB4GPOA23HMt2zt4afDiI7
+lAmuv8MKkTmBCcFe+q+U7o6wMxkjGstzAWRibtwzR4ejPwdO7se23MXCWGPvF16Z
+tu1ip+e+waRus9o5UnyGaVPFAw8iCTC/KwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
+AQB42AW7E57yOky8GpsKLoa9u7okwvvg8CQJ117X8a2MElBGnmMd9tjLa/pXAx2I
+bN7jSTSadXiPNYCx4ueiJa4Dwy+C8YkwUbhRf3+mc7Chnz0SXouTjh7OUeeA06jS
+W2VAR2pKB0pdJtAkXxIy21Juu8KF5uZqVq1oimgKw2lRUIMdKaqsrVwESk6u5Ojj
+3DS40q9DzFnwKGCuZpspvMdWYLscotzLrCbnHp+guWDigEHS3CKzKbNo327nVg6X
+7UjqqtPZ2mCsnUx3QTDJsr3gcSqhzmB+Q6I/0Q2Nx/aMmbsNegu+LC3GjFtL59Bv
+B8pB/MxID0j47SwPKQghZvb3
+-----END CERTIFICATE-----
diff --git a/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.key b/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.key
new file mode 100644
index 0000000000..8c278f843d
--- /dev/null
+++ b/src/Symfony/Component/HttpClient/Tests/Fixtures/tls/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAuKnXkBSJwOwkKfR58wP/yLYW9QFX2THoqN8iffangRmZwc5K
+LE6F1S8jYMv3JGiJ95Ij3MezAfuBCdgPqqP8JrR1XwjR1RFZMOL/4U9R9OuMVng0
+4PLwL6TzKoEtZuExHUWFP0+5AYblgno2hoN/HVuox8m6zQrBNcbhTgDIjP5Hn491
+d9odMtS3OxksDLr1UIOUGUWF7MQMN7lsN7rgT5qxoCkcAGAB4GPOA23HMt2zt4af
+DiI7lAmuv8MKkTmBCcFe+q+U7o6wMxkjGstzAWRibtwzR4ejPwdO7se23MXCWGPv
+F16Ztu1ip+e+waRus9o5UnyGaVPFAw8iCTC/KwIDAQABAoIBAQCczVNGe7oRADMh
+EP/wM4ghhUTvHAndWrzFkFs4fJX1UKi34ZQoFTEdOZ6f1fHwj3f/qa8cDNJar5X9
+puJ+siotL3Suks2iT83dbhN63SCpiM2sqvuzu3Xp7vWwNOo5fqR2x46CmQ5uVn5S
+EbZ09/mbEza5FvmwnB49rLepxY6F8P+vK5ZnCZYS2SHpOxv3U9wG8gmcHRI9ejbC
+X9rwuu3oT23bfbJ0tn6Qh8O3R1kXZUUXqnxsn554cZZrXg5+ygbt4HfDVWMLpqy/
+5wG0FCpU8QvjF4L8qErP7TZRrWGFtti1RtACbu9LrWvO/74v54td5V28U6kqlDJR
+ff4Mi4whAoGBAOBzReQIxGwoYApPyhF+ohvF39JEEXYfkzk94t6hbgyBFBFvqdFY
+shT59im2P9LyDvTd5DnCIo52Sj7vM9H80tRjAA0A8okGOczk31ABbH8aZ2orU/0G
+EJe4PV4r3bpLO6DKTYsicgRpXI3aHHLvYFXOVNrQKfrKCQ+GFMVuhDdRAoGBANKe
+3Dn3XOq7EW42GZey1xUxrfQRJp491KXHvjYt7z7zSiUzqN+mqIqz6ngCjJWbyQsl
+Ud9N9U+4rNfYYLHQ0resjxGQRtmooOHlLhT6pEplXDgQb2SmCg2u22SKkkXA7zOV
+OFbNryXgkYThsA6ih8LiKM8aFn7zttRSEeTpfye7AoGBALhIzRyiuiuXpuswgdeF
+YrJs8A1jB/c1i5qXHlvurT2lCYYbaZHSQj0I0r2CvrqDNhaEzStDIz5XDzTHD4Qd
+EjmBo3wJyBkLPI/nZxb4ZE2jrz8znf0EasE3a2OTnrSjqqylDa/sMzM+EtkBORSB
+SFaLV45lFeKs2W2eiBVmXTZRAoGAJoA7qaz6Iz6G9SqWixB6GLm4HsFz2cFbueJF
+dwn2jf9TMnG7EQcaECDLX5y3rjGIEq2DxdouWaBcmChJpLeTjVfR31gMW4Vjw2dt
+gRBAMAlPTkBS3Ictl0q7eCmMi4u1Liy828FFnxrp/uxyjnpPbuSAqTsPma1bYnyO
+INY+FDkCgYAe9e39/vXe7Un3ysjqDUW+0OMM+kg4ulhiopzKY+QbHiSWmUUDtvcN
+asqrYiX1d59e2ZNiqrlBn86I8549St81bWSrRMNf7R+WVb79RApsABeUaEoyo3lq
+0UgOBM8Nt558kaja/YfJf/jwNC1DPuu5x5t38ZcqAkqrZ/HEPkFdGQ==
+-----END RSA PRIVATE KEY-----
diff --git a/src/Symfony/Component/HttpClient/TraceableHttpClient.php b/src/Symfony/Component/HttpClient/TraceableHttpClient.php
index 4acbc8ee42..d60d0849cd 100644
--- a/src/Symfony/Component/HttpClient/TraceableHttpClient.php
+++ b/src/Symfony/Component/HttpClient/TraceableHttpClient.php
@@ -14,11 +14,12 @@ namespace Symfony\Component\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
+use Symfony\Contracts\Service\ResetInterface;
/**
* @author Jérémy Romey
*/
-final class TraceableHttpClient implements HttpClientInterface
+final class TraceableHttpClient implements HttpClientInterface, ResetInterface
{
private $client;
private $tracedRequests = [];
@@ -68,6 +69,10 @@ final class TraceableHttpClient implements HttpClientInterface
public function reset()
{
+ if ($this->client instanceof ResetInterface) {
+ $this->client->reset();
+ }
+
$this->tracedRequests = [];
}
}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
index bb99c475b5..37302128ad 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
@@ -91,7 +91,10 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
return 'memory';
}
- private function convertToBytes(string $memoryLimit): int
+ /**
+ * @return int|float
+ */
+ private function convertToBytes(string $memoryLimit)
{
if ('-1' === $memoryLimit) {
return -1;
diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ResettableServicePass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ResettableServicePass.php
index c1199f639e..b5e46106a7 100644
--- a/src/Symfony/Component/HttpKernel/DependencyInjection/ResettableServicePass.php
+++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ResettableServicePass.php
@@ -43,16 +43,21 @@ class ResettableServicePass implements CompilerPassInterface
foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) {
$services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE);
- $attributes = $tags[0];
- if (!isset($attributes['method'])) {
- throw new RuntimeException(sprintf('Tag %s requires the "method" attribute to be set.', $this->tagName));
+ foreach ($tags as $attributes) {
+ if (!isset($attributes['method'])) {
+ throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName));
+ }
+
+ if (!isset($methods[$id])) {
+ $methods[$id] = [];
+ }
+
+ $methods[$id][] = $attributes['method'];
}
-
- $methods[$id] = $attributes['method'];
}
- if (empty($services)) {
+ if (!$services) {
$container->removeAlias('services_resetter');
$container->removeDefinition('services_resetter');
diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ServicesResetter.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ServicesResetter.php
index 734fadbd74..d9e0028ce1 100644
--- a/src/Symfony/Component/HttpKernel/DependencyInjection/ServicesResetter.php
+++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ServicesResetter.php
@@ -35,7 +35,9 @@ class ServicesResetter implements ResetInterface
public function reset()
{
foreach ($this->resettableServices as $id => $service) {
- $service->{$this->resetMethods[$id]}();
+ foreach ((array) $this->resetMethods[$id] as $resetMethod) {
+ $service->$resetMethod();
+ }
}
}
}
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
index 9475c47992..698af72ce2 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
@@ -377,7 +377,9 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
}
// add our cached last-modified validator
- $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified'));
+ if ($entry->headers->has('Last-Modified')) {
+ $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified'));
+ }
// Add our cached etag validator to the environment.
// We keep the etags from the client to handle the case when the client
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 0bf90dbbce..cc23624d33 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -433,8 +433,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
try {
if (file_exists($cachePath) && \is_object($this->container = include $cachePath)
- && (!$this->debug || (self::$freshCache[$k = $cachePath.'.'.$this->environment] ?? self::$freshCache[$k] = $cache->isFresh()))
+ && (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh()))
) {
+ self::$freshCache[$cachePath] = true;
$this->container->set('kernel', $this);
error_reporting($errorLevel);
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php
index d3c6869320..9dbc2b08a4 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php
@@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
+use Symfony\Component\HttpKernel\Tests\Fixtures\MultiResettableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ResettableServicePassTest extends TestCase
@@ -23,6 +24,10 @@ class ResettableServicePassTest extends TestCase
$container->register('two', ClearableService::class)
->setPublic(true)
->addTag('kernel.reset', ['method' => 'clear']);
+ $container->register('three', MultiResettableService::class)
+ ->setPublic(true)
+ ->addTag('kernel.reset', ['method' => 'resetFirst'])
+ ->addTag('kernel.reset', ['method' => 'resetSecond']);
$container->register('services_resetter', ServicesResetter::class)
->setPublic(true)
@@ -38,10 +43,12 @@ class ResettableServicePassTest extends TestCase
new IteratorArgument([
'one' => new Reference('one', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
'two' => new Reference('two', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
+ 'three' => new Reference('three', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
]),
[
- 'one' => 'reset',
- 'two' => 'clear',
+ 'one' => ['reset'],
+ 'two' => ['clear'],
+ 'three' => ['resetFirst', 'resetSecond'],
],
],
$definition->getArguments()
@@ -51,7 +58,7 @@ class ResettableServicePassTest extends TestCase
public function testMissingMethod()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
- $this->expectExceptionMessage('Tag kernel.reset requires the "method" attribute to be set.');
+ $this->expectExceptionMessage('Tag "kernel.reset" requires the "method" attribute to be set.');
$container = new ContainerBuilder();
$container->register(ResettableService::class)
->addTag('kernel.reset');
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ServicesResetterTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ServicesResetterTest.php
index 5be6026c90..604d2b0d13 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ServicesResetterTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ServicesResetterTest.php
@@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
+use Symfony\Component\HttpKernel\Tests\Fixtures\MultiResettableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ServicesResetterTest extends TestCase
@@ -22,6 +23,8 @@ class ServicesResetterTest extends TestCase
{
ResettableService::$counter = 0;
ClearableService::$counter = 0;
+ MultiResettableService::$resetFirstCounter = 0;
+ MultiResettableService::$resetSecondCounter = 0;
}
public function testResetServices()
@@ -29,14 +32,18 @@ class ServicesResetterTest extends TestCase
$resetter = new ServicesResetter(new \ArrayIterator([
'id1' => new ResettableService(),
'id2' => new ClearableService(),
+ 'id3' => new MultiResettableService(),
]), [
- 'id1' => 'reset',
- 'id2' => 'clear',
+ 'id1' => ['reset'],
+ 'id2' => ['clear'],
+ 'id3' => ['resetFirst', 'resetSecond'],
]);
$resetter->reset();
- $this->assertEquals(1, ResettableService::$counter);
- $this->assertEquals(1, ClearableService::$counter);
+ $this->assertSame(1, ResettableService::$counter);
+ $this->assertSame(1, ClearableService::$counter);
+ $this->assertSame(1, MultiResettableService::$resetFirstCounter);
+ $this->assertSame(1, MultiResettableService::$resetSecondCounter);
}
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/MultiResettableService.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/MultiResettableService.php
new file mode 100644
index 0000000000..4930fd6a30
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/MultiResettableService.php
@@ -0,0 +1,19 @@
+setNextResponse(200, [], 'Hello World', function ($request, $response) {
+ $this->assertFalse($request->headers->has('If-Modified-Since'));
$response->headers->set('Cache-Control', 'public');
$response->headers->set('ETag', '"12345"');
if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) {
diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
index e185c6f862..e9f100a8af 100644
--- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
@@ -29,7 +29,7 @@ use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class KernelTest extends TestCase
{
- public static function tearDownAfterClass(): void
+ protected function tearDown(): void
{
$fs = new Filesystem();
$fs->remove(__DIR__.'/Fixtures/var');
diff --git a/src/Symfony/Component/Intl/Currencies.php b/src/Symfony/Component/Intl/Currencies.php
index 7459d633cb..c155c8f09f 100644
--- a/src/Symfony/Component/Intl/Currencies.php
+++ b/src/Symfony/Component/Intl/Currencies.php
@@ -46,7 +46,7 @@ final class Currencies extends ResourceBundle
}
/**
- * @throws MissingResourceException if the currency code does not exists
+ * @throws MissingResourceException if the currency code does not exist
*/
public static function getName(string $currency, string $displayLocale = null): string
{
@@ -78,7 +78,7 @@ final class Currencies extends ResourceBundle
}
/**
- * @throws MissingResourceException if the currency code does not exists
+ * @throws MissingResourceException if the currency code does not exist
*/
public static function getSymbol(string $currency, string $displayLocale = null): string
{
@@ -115,7 +115,7 @@ final class Currencies extends ResourceBundle
}
/**
- * @throws MissingResourceException if the numeric code does not exists
+ * @throws MissingResourceException if the numeric code does not exist
*/
public static function forNumericCode(int $numericCode): array
{
diff --git a/src/Symfony/Component/Intl/Locales.php b/src/Symfony/Component/Intl/Locales.php
index aee16beb16..1b2d0d2adf 100644
--- a/src/Symfony/Component/Intl/Locales.php
+++ b/src/Symfony/Component/Intl/Locales.php
@@ -49,7 +49,7 @@ final class Locales extends ResourceBundle
}
/**
- * @throws MissingResourceException if the locale does not exists
+ * @throws MissingResourceException if the locale does not exist
*/
public static function getName(string $locale, string $displayLocale = null): string
{
diff --git a/src/Symfony/Component/Intl/Scripts.php b/src/Symfony/Component/Intl/Scripts.php
index 943ef8b469..bb29f0095b 100644
--- a/src/Symfony/Component/Intl/Scripts.php
+++ b/src/Symfony/Component/Intl/Scripts.php
@@ -41,7 +41,7 @@ final class Scripts extends ResourceBundle
}
/**
- * @throws MissingResourceException if the script code does not exists
+ * @throws MissingResourceException if the script code does not exist
*/
public static function getName(string $script, string $displayLocale = null): string
{
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
index 2c90472fc6..17f7a7fcf3 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
@@ -60,7 +60,7 @@ class MandrillHttpTransport extends AbstractHttpTransport
throw new HttpTransportException(sprintf('Unable to send an email (code %s).', $result['code']), $response);
}
- $message->setMessageId($result['_id']);
+ $message->setMessageId($result[0]['_id']);
return $response;
}
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php
index 60d5e806e3..b3cb7a6dc8 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php
@@ -28,6 +28,9 @@ class AmqpTransportFactoryTest extends TestCase
$this->assertFalse($factory->supports('invalid-dsn', []));
}
+ /**
+ * @requires extension amqp
+ */
public function testItCreatesTheTransport()
{
$factory = new AmqpTransportFactory();
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php
index 22149f8a39..6fddc3fbbc 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\Messenger\Tests\Transport;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
+use Symfony\Component\Messenger\Tests\Fixtures\AnEnvelopeStamp;
use Symfony\Component\Messenger\Transport\InMemoryTransport;
/**
@@ -50,6 +51,19 @@ class InMemoryTransportTest extends TestCase
$this->assertSame([], $this->transport->get());
}
+ public function testAcknowledgeSameMessageWithDifferentStamps()
+ {
+ $envelope1 = new Envelope(new \stdClass(), [new AnEnvelopeStamp()]);
+ $this->transport->send($envelope1);
+ $envelope2 = new Envelope(new \stdClass(), [new AnEnvelopeStamp()]);
+ $this->transport->send($envelope2);
+ $this->assertSame([$envelope1, $envelope2], $this->transport->get());
+ $this->transport->ack($envelope1->with(new AnEnvelopeStamp()));
+ $this->assertSame([$envelope2], $this->transport->get());
+ $this->transport->reject($envelope2->with(new AnEnvelopeStamp()));
+ $this->assertSame([], $this->transport->get());
+ }
+
public function testAck()
{
$envelope = new Envelope(new \stdClass());
diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
index 8e37e3873f..6d4db85b0b 100644
--- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger\Transport\AmqpExt;
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
+use Symfony\Component\Messenger\Exception\LogicException;
/**
* An AMQP connection.
@@ -58,6 +59,10 @@ class Connection
public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, AmqpFactory $amqpFactory = null)
{
+ if (!\extension_loaded('amqp')) {
+ throw new LogicException(sprintf('You cannot use the "%s" as the "amqp" extension is not installed.', __CLASS__));
+ }
+
$this->connectionOptions = array_replace_recursive([
'delay' => [
'exchange_name' => 'delays',
diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php
index 4541a1095d..50e95ef5e2 100644
--- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php
+++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger\Transport\Doctrine;
use Doctrine\Common\Persistence\ConnectionRegistry;
+use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\Messenger\Exception\TransportException;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
@@ -24,8 +25,12 @@ class DoctrineTransportFactory implements TransportFactoryInterface
{
private $registry;
- public function __construct(ConnectionRegistry $registry)
+ public function __construct($registry)
{
+ if (!$registry instanceof RegistryInterface && !$registry instanceof ConnectionRegistry) {
+ throw new \TypeError(sprintf('Expected an instance of %s or %s, but got %s.', RegistryInterface::class, ConnectionRegistry::class, \is_object($registry) ? \get_class($registry) : \gettype($registry)));
+ }
+
$this->registry = $registry;
}
diff --git a/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php
index 354bb601a1..09cbb31a04 100644
--- a/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php
+++ b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php
@@ -55,7 +55,7 @@ class InMemoryTransport implements TransportInterface, ResetInterface
public function ack(Envelope $envelope): void
{
$this->acknowledged[] = $envelope;
- $id = spl_object_hash($envelope);
+ $id = spl_object_hash($envelope->getMessage());
unset($this->queue[$id]);
}
@@ -65,7 +65,7 @@ class InMemoryTransport implements TransportInterface, ResetInterface
public function reject(Envelope $envelope): void
{
$this->rejected[] = $envelope;
- $id = spl_object_hash($envelope);
+ $id = spl_object_hash($envelope->getMessage());
unset($this->queue[$id]);
}
@@ -75,7 +75,7 @@ class InMemoryTransport implements TransportInterface, ResetInterface
public function send(Envelope $envelope): Envelope
{
$this->sent[] = $envelope;
- $id = spl_object_hash($envelope);
+ $id = spl_object_hash($envelope->getMessage());
$this->queue[$id] = $envelope;
return $envelope;
diff --git a/src/Symfony/Component/Routing/Loader/ObjectLoader.php b/src/Symfony/Component/Routing/Loader/ObjectLoader.php
index aefb829511..1a375d95ff 100644
--- a/src/Symfony/Component/Routing/Loader/ObjectLoader.php
+++ b/src/Symfony/Component/Routing/Loader/ObjectLoader.php
@@ -42,10 +42,15 @@ abstract class ObjectLoader extends Loader
*/
public function load($resource, string $type = null)
{
- if (!preg_match('/^[^\:]+(?:::(?:[^\:]+))?$/', $resource)) {
+ if (!preg_match('/^[^\:]+(?:::?(?:[^\:]+))?$/', $resource)) {
throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object'));
}
+ if (1 === substr_count($resource, ':')) {
+ $resource = str_replace(':', '::', $resource);
+ @trigger_error(sprintf('Referencing object route loaders with a single colon is deprecated since Symfony 4.1. Use %s instead.', $resource), E_USER_DEPRECATED);
+ }
+
$parts = explode('::', $resource);
$method = $parts[1] ?? '__invoke';
diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php
index eadd23f91e..6eaee110d0 100644
--- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php
@@ -144,7 +144,6 @@ class SwitchUserListener
try {
$this->provider->loadUserByUsername($nonExistentUsername);
- throw new \LogicException('AuthenticationException expected');
} catch (AuthenticationException $e) {
}
} catch (AuthenticationException $e) {
diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php
index 15b535b0c7..b32a04b5a9 100644
--- a/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php
+++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php
@@ -27,7 +27,7 @@ trait ClassResolverTrait
*
* @param object|string $value
*
- * @throws InvalidArgumentException If the class does not exists
+ * @throws InvalidArgumentException If the class does not exist
*/
private function getClass($value): string
{
diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php
index 224c7edd41..b349d8675d 100644
--- a/src/Symfony/Component/Validator/Constraint.php
+++ b/src/Symfony/Component/Validator/Constraint.php
@@ -287,7 +287,7 @@ abstract class Constraint
*
* @internal
*/
- public function __sleep(): array
+ public function __sleep()
{
// Initialize "groups" option if it is not set
$this->groups;
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
index 5a391a2e66..21e2392c7d 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
@@ -362,6 +362,10 @@
This password has been leaked in a data breach, it must not be used. Please use another password.
このパスワードは漏洩している為使用できません。
+
+ This value should be between {{ min }} and {{ max }}.
+ {{ min }}以上{{ max }}以下でなければなりません。
+