diff --git a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
index d4a86a7d54..ee4c644f0e 100644
--- a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
+++ b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
@@ -138,6 +138,9 @@ class DoctrineDataCollector extends DataCollector
if (!\is_array($query['params'])) {
$query['params'] = [$query['params']];
}
+ if (!\is_array($query['types'])) {
+ $query['types'] = [];
+ }
foreach ($query['params'] as $j => $param) {
if (isset($query['types'][$j])) {
// Transform the param according to the type
diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php
index 945e1fd245..b0ff88410d 100644
--- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php
+++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php
@@ -13,7 +13,9 @@ namespace Symfony\Bridge\Doctrine\Messenger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Envelope;
+use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\Middleware\StackInterface;
+use Symfony\Component\Messenger\Stamp\HandledStamp;
/**
* Wraps all handlers in a single doctrine transaction.
@@ -36,6 +38,12 @@ class DoctrineTransactionMiddleware extends AbstractDoctrineMiddleware
} catch (\Throwable $exception) {
$entityManager->getConnection()->rollBack();
+ if ($exception instanceof HandlerFailedException) {
+ // Remove all HandledStamp from the envelope so the retry will execute all handlers again.
+ // When a handler fails, the queries of allegedly successful previous handlers just got rolled back.
+ throw new HandlerFailedException($exception->getEnvelope()->withoutAll(HandledStamp::class), $exception->getNestedExceptions());
+ }
+
throw $exception;
}
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
index 95e0e715ff..6a33f0680a 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
@@ -102,6 +102,18 @@ class DoctrineDataCollectorTest extends TestCase
$this->assertTrue($collectedQueries['default'][1]['explainable']);
}
+ public function testCollectQueryWithNoTypes()
+ {
+ $queries = [
+ ['sql' => 'SET sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))', 'params' => [], 'types' => null, 'executionMS' => 1],
+ ];
+ $c = $this->createCollector($queries);
+ $c->collect(new Request(), new Response());
+
+ $collectedQueries = $c->getQueries();
+ $this->assertSame([], $collectedQueries['default'][0]['types']);
+ }
+
public function testReset()
{
$queries = [
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index 55089e0be1..f9457c937d 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -139,10 +139,13 @@ class DeprecationErrorHandler
$group = 'unsilenced';
} elseif ($deprecation->isLegacy(self::$utilPrefix)) {
$group = 'legacy';
- } elseif (!$deprecation->isSelf()) {
- $group = $deprecation->isIndirect() ? 'remaining indirect' : 'remaining direct';
} else {
- $group = 'remaining self';
+ $group = [
+ Deprecation::TYPE_SELF => 'remaining self',
+ Deprecation::TYPE_DIRECT => 'remaining direct',
+ Deprecation::TYPE_INDIRECT => 'remaining indirect',
+ Deprecation::TYPE_UNDETERMINED => 'other',
+ ][$deprecation->getType()];
}
if ($this->getConfiguration()->shouldDisplayStackTrace($msg)) {
@@ -216,7 +219,13 @@ class DeprecationErrorHandler
return $this->configuration;
}
if (false === $mode = $this->mode) {
- $mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
+ if (isset($_SERVER['SYMFONY_DEPRECATIONS_HELPER'])) {
+ $mode = $_SERVER['SYMFONY_DEPRECATIONS_HELPER'];
+ } elseif (isset($_ENV['SYMFONY_DEPRECATIONS_HELPER'])) {
+ $mode = $_ENV['SYMFONY_DEPRECATIONS_HELPER'];
+ } else {
+ $mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
+ }
}
if ('strict' === $mode) {
return $this->configuration = Configuration::inStrictMode();
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
index ba9e753c7b..6d5b39fd54 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
@@ -18,6 +18,15 @@ use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor;
*/
class Deprecation
{
+ const PATH_TYPE_VENDOR = 'path_type_vendor';
+ const PATH_TYPE_SELF = 'path_type_internal';
+ const PATH_TYPE_UNDETERMINED = 'path_type_undetermined';
+
+ const TYPE_SELF = 'type_self';
+ const TYPE_DIRECT = 'type_direct';
+ const TYPE_INDIRECT = 'type_indirect';
+ const TYPE_UNDETERMINED = 'type_undetermined';
+
/**
* @var array
*/
@@ -39,13 +48,21 @@ class Deprecation
private $originMethod;
/**
- * @var bool
+ * @var string one of the PATH_TYPE_* constants
*/
- private $self;
+ private $triggeringFilePathType;
/** @var string[] absolute paths to vendor directories */
private static $vendors;
+ /**
+ * @var string[] absolute paths to source or tests of the project. This
+ * excludes cache directories, because it is based on
+ * autoloading rules and cache systems typically do not use
+ * those.
+ */
+ private static $internalPaths;
+
/**
* @param string $message
* @param string $file
@@ -59,7 +76,7 @@ class Deprecation
// No-op
}
$line = $trace[$i];
- $this->self = !$this->pathOriginatesFromVendor($file);
+ $this->trigerringFilePathType = $this->getPathType($file);
if (isset($line['object']) || isset($line['class'])) {
if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) {
$parsedMsg = unserialize($this->message);
@@ -70,8 +87,9 @@ class Deprecation
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
// then we need to use the serialized information to determine
// if the error has been triggered from vendor code.
- $this->self = isset($parsedMsg['triggering_file'])
- && $this->pathOriginatesFromVendor($parsedMsg['triggering_file']);
+ if (isset($parsedMsg['triggering_file'])) {
+ $this->trigerringFilePathType = $this->getPathType($parsedMsg['triggering_file']);
+ }
return;
}
@@ -101,14 +119,6 @@ class Deprecation
return isset($this->originClass);
}
- /**
- * @return bool
- */
- public function isSelf()
- {
- return $this->self;
- }
-
/**
* @return string
*/
@@ -163,10 +173,16 @@ class Deprecation
* Tells whether both the calling package and the called package are vendor
* packages.
*
- * @return bool
+ * @return string
*/
- public function isIndirect()
+ public function getType()
{
+ if (self::PATH_TYPE_SELF === $this->trigerringFilePathType) {
+ return self::TYPE_SELF;
+ }
+ if (self::PATH_TYPE_UNDETERMINED === $this->trigerringFilePathType) {
+ return self::TYPE_UNDETERMINED;
+ }
$erroringFile = $erroringPackage = null;
foreach ($this->trace as $line) {
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
@@ -179,13 +195,16 @@ class Deprecation
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
continue;
}
- if (!$this->pathOriginatesFromVendor($file)) {
- return false;
+ if (self::PATH_TYPE_SELF === $this->getPathType($file)) {
+ return self::TYPE_DIRECT;
+ }
+ if (self::PATH_TYPE_UNDETERMINED === $this->getPathType($file)) {
+ return self::TYPE_UNDETERMINED;
}
if (null !== $erroringFile && null !== $erroringPackage) {
$package = $this->getPackage($file);
if ('composer' !== $package && $package !== $erroringPackage) {
- return true;
+ return self::TYPE_INDIRECT;
}
continue;
}
@@ -193,11 +212,11 @@ class Deprecation
$erroringPackage = $this->getPackage($file);
}
- return false;
+ return self::TYPE_DIRECT;
}
/**
- * pathOriginatesFromVendor() should always be called prior to calling this method.
+ * getPathType() should always be called prior to calling this method.
*
* @param string $path
*
@@ -237,6 +256,15 @@ class Deprecation
$v = \dirname(\dirname($r->getFileName()));
if (file_exists($v.'/composer/installed.json')) {
self::$vendors[] = $v;
+ $loader = require $v.'/autoload.php';
+ $paths = self::getSourcePathsFromPrefixes(array_merge($loader->getPrefixes(), $loader->getPrefixesPsr4()));
+ }
+ }
+ }
+ foreach ($paths as $path) {
+ foreach (self::$vendors as $vendor) {
+ if (0 !== strpos($path, $vendor)) {
+ self::$internalPaths[] = $path;
}
}
}
@@ -245,24 +273,41 @@ class Deprecation
return self::$vendors;
}
+ private static function getSourcePathsFromPrefixes(array $prefixesByNamespace)
+ {
+ foreach ($prefixesByNamespace as $prefixes) {
+ foreach ($prefixes as $prefix) {
+ if (false !== realpath($prefix)) {
+ yield realpath($prefix);
+ }
+ }
+ }
+ }
+
/**
* @param string $path
*
- * @return bool
+ * @return string
*/
- private function pathOriginatesFromVendor($path)
+ private function getPathType($path)
{
$realPath = realpath($path);
if (false === $realPath && '-' !== $path && 'Standard input code' !== $path) {
- return true;
+ return self::PATH_TYPE_UNDETERMINED;
}
foreach (self::getVendors() as $vendor) {
if (0 === strpos($realPath, $vendor) && false !== strpbrk(substr($realPath, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
- return true;
+ return self::PATH_TYPE_VENDOR;
}
}
- return false;
+ foreach (self::$internalPaths as $internalPath) {
+ if (0 === strpos($realPath, $internalPath)) {
+ return self::PATH_TYPE_SELF;
+ }
+ }
+
+ return self::PATH_TYPE_UNDETERMINED;
}
/**
@@ -281,19 +326,4 @@ class Deprecation
"\n".str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $exception->getTraceAsString()).
"\n";
}
-
- private function getPackageFromLine(array $line)
- {
- if (!isset($line['file'])) {
- return 'internal function';
- }
- if (!$this->pathOriginatesFromVendor($line['file'])) {
- return 'source code';
- }
- try {
- return $this->getPackage($line['file']);
- } catch (\RuntimeException $e) {
- return 'unknown';
- }
- }
}
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
index 92bad71e08..583cca22f4 100644
--- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
@@ -27,7 +27,7 @@ class DeprecationTest extends TestCase
public function testItCanTellWhetherItIsInternal()
{
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
- $this->assertTrue($deprecation->isSelf());
+ $this->assertSame(Deprecation::TYPE_SELF, $deprecation->getType());
}
public function testLegacyTestMethodIsDetectedAsSuch()
@@ -46,7 +46,7 @@ class DeprecationTest extends TestCase
public function testItRulesOutFilesOutsideVendorsAsIndirect()
{
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
- $this->assertFalse($deprecation->isIndirect());
+ $this->assertNotSame(Deprecation::TYPE_INDIRECT, $deprecation->getType());
}
/**
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt
index e9f7bec966..126d23389a 100644
--- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt
@@ -73,15 +73,13 @@ Unsilenced deprecation notices (3)
1x: unsilenced bar deprecation
1x in FooTestCase::testNonLegacyBar
-Remaining self deprecation notices (1)
+Legacy deprecation notices (1)
+
+Other deprecation notices (2)
+
+ 1x: root deprecation
1x: silenced bar deprecation
1x in FooTestCase::testNonLegacyBar
-Legacy deprecation notices (1)
-
-Other deprecation notices (1)
-
- 1x: root deprecation
-
I get precedence over any exit statements inside the deprecation error handler.
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled.phpt
index 0115bbd242..a55e88d1a8 100644
--- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled.phpt
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled.phpt
@@ -1,9 +1,9 @@
--TEST--
-Test DeprecationErrorHandler in weak mode
+Test DeprecationErrorHandler in disabled mode
--FILE--
+--EXPECTF--
+00
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled_from_putenv.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled_from_putenv.phpt
new file mode 100644
index 0000000000..73a67241a4
--- /dev/null
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/disabled_from_putenv.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Test DeprecationErrorHandler in disabled mode (via putenv)
+--FILE--
+
+--EXPECTF--
+00
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/autoload.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/autoload.php
index bf315f2eaa..3c4471bcbe 100644
--- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/autoload.php
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/autoload.php
@@ -1,3 +1,5 @@
{{- form_label(form) }} {# -#}
{{ form_widget(form, widget_attr) }} {# -#}
+ {{- form_help(form) -}}
{{ form_errors(form) }} {# -#}
{# -#}
{%- endblock form_row %}
diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php
index a183e82cf8..8309db19ec 100644
--- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php
+++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php
@@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\VarDumper\Caster\ReflectionCaster;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
@@ -43,9 +44,9 @@ class DebugExtension extends Extension
->addMethodCall('setMinDepth', [$config['min_depth']])
->addMethodCall('setMaxString', [$config['max_string_length']]);
- if (method_exists(ReflectionClass::class, 'unsetClosureFileInfo')) {
+ if (method_exists(ReflectionCaster::class, 'unsetClosureFileInfo')) {
$container->getDefinition('var_dumper.cloner')
- ->addMethodCall('addCasters', ReflectionClass::UNSET_CLOSURE_FILE_INFO);
+ ->addMethodCall('addCasters', [ReflectionCaster::UNSET_CLOSURE_FILE_INFO]);
}
if (method_exists(HtmlDumper::class, 'setTheme') && 'dark' !== $config['theme']) {
diff --git a/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php b/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php
index cd6084c5e3..c09ed8bc8c 100644
--- a/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php
+++ b/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php
@@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Bundle\DebugBundle\DependencyInjection\DebugExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
+use Symfony\Component\VarDumper\Caster\ReflectionCaster;
class DebugExtensionTest extends TestCase
{
@@ -36,6 +37,39 @@ class DebugExtensionTest extends TestCase
$this->assertSame($expectedTags, $container->getDefinition('data_collector.dump')->getTag('data_collector'));
}
+ public function testUnsetClosureFileInfoShouldBeRegisteredInVarCloner()
+ {
+ if (!method_exists(ReflectionCaster::class, 'unsetClosureFileInfo')) {
+ $this->markTestSkipped('Method not available');
+ }
+
+ $container = $this->createContainer();
+ $container->registerExtension(new DebugExtension());
+ $container->loadFromExtension('debug', []);
+ $this->compileContainer($container);
+
+ $definition = $container->getDefinition('var_dumper.cloner');
+
+ $called = false;
+ foreach ($definition->getMethodCalls() as $call) {
+ if ('addCasters' !== $call[0]) {
+ continue;
+ }
+
+ $argument = $call[1][0] ?? null;
+ if (null === $argument) {
+ continue;
+ }
+
+ if (['Closure' => ReflectionCaster::class.'::unsetClosureFileInfo'] === $argument) {
+ $called = true;
+ break;
+ }
+ }
+
+ $this->assertTrue($called);
+ }
+
private function createContainer()
{
$container = new ContainerBuilder(new ParameterBag([
diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index a405c199d6..52489f7ac2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -23,7 +23,7 @@ CHANGELOG
* [BC Break] When using Messenger, the default transport changed from
using Symfony's serializer service to use `PhpSerializer`, which uses
PHP's native `serialize()` and `unserialize()` functions. To use the
- original serialization method, set the `framework.messenger.defaut_serializer`
+ original serialization method, set the `framework.messenger.default_serializer`
config option to `messenger.transport.symfony_serializer`. Or set the
`serializer` option under one specific `transport`.
* [BC Break] The `framework.messenger.serializer` config key changed to
diff --git a/src/Symfony/Bundle/FrameworkBundle/Client.php b/src/Symfony/Bundle/FrameworkBundle/Client.php
index f33808db04..3e395a4904 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Client.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Client.php
@@ -66,7 +66,7 @@ class Client extends HttpKernelBrowser
*/
public function getProfile()
{
- if (!$this->kernel->getContainer()->has('profiler')) {
+ if (null === $this->response || !$this->kernel->getContainer()->has('profiler')) {
return false;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index cea61eddd1..db9658088c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -652,6 +652,10 @@ class FrameworkExtension extends Extension
$definitionDefinition->addArgument($transitions);
$definitionDefinition->addArgument($initialMarking);
$definitionDefinition->addArgument($metadataStoreDefinition);
+ $definitionDefinition->addTag('workflow.definition', [
+ 'name' => $name,
+ 'type' => $type,
+ ]);
// Create MarkingStore
if (isset($workflow['marking_store']['type'])) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 59e45d2ae7..ef1932133e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -311,6 +311,8 @@ abstract class FrameworkExtensionTest extends TestCase
$workflowDefinition->getArgument(0),
'Places are passed to the workflow definition'
);
+
+ $this->assertSame(['workflow.definition' => [['name' => 'legacy', 'type' => 'state_machine']]], $workflowDefinition->getTags());
}
/**
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php
index c5252c0d58..2768b59a1c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php
@@ -28,9 +28,9 @@ class ProfilerTest extends WebTestCase
// enable the profiler for the next request
$client->enableProfiler();
- $crawler = $client->request('GET', '/profiler');
- $profile = $client->getProfile();
- $this->assertInternalType('object', $profile);
+ $this->assertFalse($client->getProfile());
+ $client->request('GET', '/profiler');
+ $this->assertInternalType('object', $client->getProfile());
$client->request('GET', '/profiler');
$this->assertFalse($client->getProfile());
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index de007cd0b5..3e57b8e6c9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -48,7 +48,7 @@
"symfony/security-http": "^3.4|^4.0|^5.0",
"symfony/serializer": "^4.3|^5.0",
"symfony/stopwatch": "^3.4|^4.0|^5.0",
- "symfony/translation": "^4.2|^5.0",
+ "symfony/translation": "^4.3|^5.0",
"symfony/templating": "^3.4|^4.0|^5.0",
"symfony/twig-bundle": "^3.4|^4.0|^5.0",
"symfony/validator": "^4.1|^5.0",
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
index 788fe59d93..8097e49cfd 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
@@ -12,8 +12,8 @@
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\SimpleCacheAdapter;
-use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\ArrayCache;
+use Symfony\Component\Cache\Simple\FilesystemCache;
/**
* @group time-sensitive
diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
index 63039d5660..1554293e19 100644
--- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
@@ -314,7 +314,7 @@ class DotenvTest extends TestCase
$dotenv->load(__DIR__);
}
- public function testServerSuperglobalIsNotOverriden()
+ public function testServerSuperglobalIsNotOverridden()
{
$originalValue = $_SERVER['argc'];
@@ -324,7 +324,7 @@ class DotenvTest extends TestCase
$this->assertSame($originalValue, $_SERVER['argc']);
}
- public function testEnvVarIsNotOverriden()
+ public function testEnvVarIsNotOverridden()
{
putenv('TEST_ENV_VAR=original_value');
$_SERVER['TEST_ENV_VAR'] = 'original_value';
@@ -335,7 +335,7 @@ class DotenvTest extends TestCase
$this->assertSame('original_value', getenv('TEST_ENV_VAR'));
}
- public function testHttpVarIsPartiallyOverriden()
+ public function testHttpVarIsPartiallyOverridden()
{
$_SERVER['HTTP_TEST_ENV_VAR'] = 'http_value';
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index d83b27330c..dd3d8b471e 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -569,14 +569,15 @@ class Filesystem
}
$this->mkdir($targetDir);
- $targetDirInfo = new \SplFileInfo($targetDir);
+ $filesCreatedWhileMirroring = [];
foreach ($iterator as $file) {
- if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || 0 === strpos($file->getRealPath(), $targetDirInfo->getRealPath())) {
+ if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) {
continue;
}
$target = $targetDir.substr($file->getPathname(), $originDirLen);
+ $filesCreatedWhileMirroring[$target] = true;
if (!$copyOnWindows && is_link($file)) {
$this->symlink($file->getLinkTarget(), $target);
diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
index a1a3ce0e6e..7fa2ecd3de 100644
--- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
+++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -1362,6 +1362,22 @@ class FilesystemTest extends FilesystemTestCase
$this->assertFalse($this->filesystem->exists($targetPath.'target'));
}
+ public function testMirrorFromSubdirectoryInToParentDirectory()
+ {
+ $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR;
+ $sourcePath = $targetPath.'bar'.\DIRECTORY_SEPARATOR;
+ $file1 = $sourcePath.'file1';
+ $file2 = $sourcePath.'file2';
+
+ $this->filesystem->mkdir($sourcePath);
+ file_put_contents($file1, 'FILE1');
+ file_put_contents($file2, 'FILE2');
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertFileEquals($file1, $targetPath.'file1');
+ }
+
/**
* @dataProvider providePathsForIsAbsolutePath
*/
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf
new file mode 100644
index 0000000000..70e8541ed9
--- /dev/null
+++ b/src/Symfony/Component/Form/Resources/translations/validators.tr.xlf
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ Form ekstra alanlar içeremez.
+
+
+
+ Yüklenen dosya boyutu çok yüksek. Lütfen daha küçük bir dosya yüklemeyi deneyin.
+
+
+
+ CSRF fişi geçersiz. Formu tekrar göndermeyi deneyin.
+
+
+
+
diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php
index 068f3eb7ba..58c1d3d65f 100644
--- a/src/Symfony/Component/HttpClient/NativeHttpClient.php
+++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php
@@ -98,9 +98,9 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
'http_code' => 0,
'redirect_count' => 0,
'start_time' => 0.0,
- 'fopen_time' => 0.0,
'connect_time' => 0.0,
'redirect_time' => 0.0,
+ 'pretransfer_time' => 0.0,
'starttransfer_time' => 0.0,
'total_time' => 0.0,
'namelookup_time' => 0.0,
@@ -118,7 +118,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
$onProgress = static function (...$progress) use ($onProgress, &$lastProgress, &$info) {
$progressInfo = $info;
$progressInfo['url'] = implode('', $info['url']);
- unset($progressInfo['fopen_time'], $progressInfo['size_body']);
+ unset($progressInfo['size_body']);
if ($progress && -1 === $progress[0]) {
// Response completed
@@ -133,14 +133,14 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
// Always register a notification callback to compute live stats about the response
$notification = static function (int $code, int $severity, ?string $msg, int $msgCode, int $dlNow, int $dlSize) use ($onProgress, &$info) {
- $now = microtime(true);
- $info['total_time'] = $now - $info['start_time'];
+ $info['total_time'] = microtime(true) - $info['start_time'];
if (STREAM_NOTIFY_PROGRESS === $code) {
+ $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time'];
$info['size_upload'] += $dlNow ? 0 : $info['size_body'];
$info['size_download'] = $dlNow;
} elseif (STREAM_NOTIFY_CONNECT === $code) {
- $info['connect_time'] += $now - $info['fopen_time'];
+ $info['connect_time'] = $info['total_time'];
$info['debug'] .= $info['request_header'];
unset($info['request_header']);
} else {
@@ -310,7 +310,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
throw new TransportException(sprintf('Could not resolve host "%s".', $host));
}
- $info['namelookup_time'] += microtime(true) - $now;
+ $info['namelookup_time'] = microtime(true) - ($info['start_time'] ?: $now);
$multi->dnsCache[$host] = $ip = $ip[0];
$info['debug'] .= "* Added {$host}:0:{$ip} to DNS cache\n";
} else {
@@ -368,10 +368,9 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
return null;
}
- $now = microtime(true);
$info['url'] = $url;
++$info['redirect_count'];
- $info['redirect_time'] = $now - $info['start_time'];
+ $info['redirect_time'] = microtime(true) - $info['start_time'];
// Do like curl and browsers: turn POST to GET on 301, 302 and 303
if (\in_array($info['http_code'], [301, 302, 303], true)) {
diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
index 14d3f935e0..30dd31f0ae 100644
--- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
@@ -55,6 +55,7 @@ final class CurlResponse implements ResponseInterface
$this->info['start_time'] = $this->info['start_time'] ?? microtime(true);
$info = &$this->info;
$headers = &$this->headers;
+ $debugBuffer = $this->debugBuffer;
if (!$info['response_headers']) {
// Used to keep track of what we're waiting for
@@ -88,9 +89,11 @@ final class CurlResponse implements ResponseInterface
if ($onProgress = $options['on_progress']) {
$url = isset($info['url']) ? ['url' => $info['url']] : [];
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
- curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi) {
+ curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi, $debugBuffer) {
try {
- $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info);
+ rewind($debugBuffer);
+ $debug = ['debug' => stream_get_contents($debugBuffer)];
+ $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info + $debug);
} catch (\Throwable $e) {
$multi->handlesActivity[(int) $ch][] = null;
$multi->handlesActivity[(int) $ch][] = $e;
@@ -148,12 +151,6 @@ final class CurlResponse implements ResponseInterface
if (!$info = $this->finalInfo) {
self::perform($this->multi);
- if ('debug' === $type) {
- rewind($this->debugBuffer);
-
- return stream_get_contents($this->debugBuffer);
- }
-
$info = array_merge($this->info, curl_getinfo($this->handle));
$info['url'] = $this->info['url'] ?? $info['url'];
$info['redirect_url'] = $this->info['redirect_url'] ?? null;
@@ -164,9 +161,10 @@ final class CurlResponse implements ResponseInterface
$info['starttransfer_time'] = 0.0;
}
+ rewind($this->debugBuffer);
+ $info['debug'] = stream_get_contents($this->debugBuffer);
+
if (!\in_array(curl_getinfo($this->handle, CURLINFO_PRIVATE), ['headers', 'content'], true)) {
- rewind($this->debugBuffer);
- $info['debug'] = stream_get_contents($this->debugBuffer);
curl_setopt($this->handle, CURLOPT_VERBOSE, false);
rewind($this->debugBuffer);
ftruncate($this->debugBuffer, 0);
@@ -289,7 +287,19 @@ final class CurlResponse implements ResponseInterface
// Regular header line: add it to the list
self::addResponseHeaders([substr($data, 0, -2)], $info, $headers);
- if (0 === strpos($data, 'HTTP') && 300 <= $info['http_code'] && $info['http_code'] < 400) {
+ if (0 !== strpos($data, 'HTTP/')) {
+ if (0 === stripos($data, 'Location:')) {
+ $location = trim(substr($data, 9, -2));
+ }
+
+ return \strlen($data);
+ }
+
+ if (\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) {
+ $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert'));
+ }
+
+ if (300 <= $info['http_code'] && $info['http_code'] < 400) {
if (curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
} elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) {
@@ -298,15 +308,14 @@ final class CurlResponse implements ResponseInterface
}
}
- if (0 === stripos($data, 'Location:')) {
- $location = trim(substr($data, 9, -2));
- }
-
return \strlen($data);
}
// End of headers: handle redirects and add to the activity list
- $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
+ if (200 > $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE)) {
+ return \strlen($data);
+ }
+
$info['redirect_url'] = null;
if (300 <= $statusCode && $statusCode < 400 && null !== $location) {
@@ -336,10 +345,6 @@ final class CurlResponse implements ResponseInterface
return 0;
}
- if (\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) {
- $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert'));
- }
-
curl_setopt($ch, CURLOPT_PRIVATE, 'content');
} elseif (null !== $info['redirect_url'] && $logger) {
$logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url']));
diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
index 8be4b04163..766506479f 100644
--- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
@@ -78,18 +78,12 @@ final class NativeResponse implements ResponseInterface
if (!$info = $this->finalInfo) {
self::perform($this->multi);
- if ('debug' === $type) {
- return $this->info['debug'];
- }
-
$info = $this->info;
$info['url'] = implode('', $info['url']);
- unset($info['fopen_time'], $info['size_body'], $info['request_header']);
+ unset($info['size_body'], $info['request_header']);
if (null === $this->buffer) {
$this->finalInfo = $info;
- } else {
- unset($info['debug']);
}
}
@@ -134,7 +128,6 @@ final class NativeResponse implements ResponseInterface
$this->info['request_header'] .= implode("\r\n", $context['http']['header'])."\r\n\r\n";
// Send request and follow redirects when needed
- $this->info['fopen_time'] = microtime(true);
$this->handle = $h = fopen($url, 'r', false, $this->context);
self::addResponseHeaders($http_response_header, $this->info, $this->headers, $this->info['debug']);
$url = ($this->resolveRedirect)($this->multi, $this->headers['location'][0] ?? null, $this->context);
@@ -152,7 +145,7 @@ final class NativeResponse implements ResponseInterface
return;
} finally {
- $this->info['starttransfer_time'] = $this->info['total_time'] = microtime(true) - $this->info['start_time'];
+ $this->info['pretransfer_time'] = $this->info['total_time'] = microtime(true) - $this->info['start_time'];
restore_error_handler();
}
@@ -273,6 +266,7 @@ final class NativeResponse implements ResponseInterface
if (null !== $e || !$remaining || feof($h)) {
// Stream completed
$info['total_time'] = microtime(true) - $info['start_time'];
+ $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time'];
if ($onProgress) {
try {
diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php
index 867ceba97f..db0b9aeb0b 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Session.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Session.php
@@ -253,7 +253,9 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function getBag($name)
{
- return $this->storage->getBag($name)->getBag();
+ $bag = $this->storage->getBag($name);
+
+ return method_exists($bag, 'getBag') ? $bag->getBag() : $bag;
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php
index afa00fc7c3..acb129984e 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php
@@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\SessionBagProxy;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
/**
@@ -260,4 +261,28 @@ class SessionTest extends TestCase
$flash->get('hello');
$this->assertTrue($this->session->isEmpty());
}
+
+ public function testGetBagWithBagImplementingGetBag()
+ {
+ $bag = new AttributeBag();
+ $bag->setName('foo');
+
+ $storage = new MockArraySessionStorage();
+ $storage->registerBag($bag);
+
+ $this->assertSame($bag, (new Session($storage))->getBag('foo'));
+ }
+
+ public function testGetBagWithBagNotImplementingGetBag()
+ {
+ $data = [];
+
+ $bag = new AttributeBag();
+ $bag->setName('foo');
+
+ $storage = new MockArraySessionStorage();
+ $storage->registerBag(new SessionBagProxy($bag, $data, $usageIndex));
+
+ $this->assertSame($bag, (new Session($storage))->getBag('foo'));
+ }
}
diff --git a/src/Symfony/Component/Lock/Store/RedisStore.php b/src/Symfony/Component/Lock/Store/RedisStore.php
index 496ce65778..39360de45c 100644
--- a/src/Symfony/Component/Lock/Store/RedisStore.php
+++ b/src/Symfony/Component/Lock/Store/RedisStore.php
@@ -71,6 +71,9 @@ class RedisStore implements StoreInterface
$this->checkNotExpired($key);
}
+ /**
+ * {@inheritdoc}
+ */
public function waitAndSave(Key $key)
{
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php
index dac472e2b0..0740050d2d 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php
@@ -68,7 +68,7 @@ class MailgunTransport extends AbstractApiTransport
{
$headers = $email->getHeaders();
$html = $email->getHtmlBody();
- if (null !== $html) {
+ if (null !== $html && \is_resource($html)) {
if (stream_get_meta_data($html)['seekable'] ?? false) {
rewind($html);
}
diff --git a/src/Symfony/Component/Mailer/Tests/TransportTest.php b/src/Symfony/Component/Mailer/Tests/TransportTest.php
index 3c15480f2c..8c7cd99d98 100644
--- a/src/Symfony/Component/Mailer/Tests/TransportTest.php
+++ b/src/Symfony/Component/Mailer/Tests/TransportTest.php
@@ -71,11 +71,18 @@ class TransportTest extends TestCase
Transport::fromDsn('some://');
}
+ public function testNoScheme()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('The "//sendmail" mailer DSN must contain a transport scheme.');
+ Transport::fromDsn('//sendmail');
+ }
+
public function testFromInvalidDsnNoHost()
{
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('The "?!" mailer DSN must contain a mailer name.');
- Transport::fromDsn('?!');
+ $this->expectExceptionMessage('The "file:///some/path" mailer DSN must contain a mailer name.');
+ Transport::fromDsn('file:///some/path');
}
public function testFromInvalidTransportName()
@@ -168,6 +175,19 @@ class TransportTest extends TestCase
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
$transport->send($message);
+ $message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html('test');
+ $client = $this->createMock(HttpClientInterface::class);
+ $client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
+ $transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
+ $transport->send($message);
+
+ $stream = fopen('data://text/plain,'.$message->getTextBody(), 'r');
+ $message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html($stream);
+ $client = $this->createMock(HttpClientInterface::class);
+ $client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
+ $transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
+ $transport->send($message);
+
$this->expectException(LogicException::class);
Transport::fromDsn('foo://mailgun');
}
diff --git a/src/Symfony/Component/Mailer/Transport.php b/src/Symfony/Component/Mailer/Transport.php
index 690608c9f3..9c703f51df 100644
--- a/src/Symfony/Component/Mailer/Transport.php
+++ b/src/Symfony/Component/Mailer/Transport.php
@@ -64,6 +64,10 @@ class Transport
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn));
}
+ if (!isset($parsedDsn['scheme'])) {
+ throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a transport scheme.', $dsn));
+ }
+
if (!isset($parsedDsn['host'])) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn));
}
diff --git a/src/Symfony/Component/Messenger/Exception/DelayedMessageHandlingException.php b/src/Symfony/Component/Messenger/Exception/DelayedMessageHandlingException.php
index 313d6f672c..4314a4f2fb 100644
--- a/src/Symfony/Component/Messenger/Exception/DelayedMessageHandlingException.php
+++ b/src/Symfony/Component/Messenger/Exception/DelayedMessageHandlingException.php
@@ -17,7 +17,7 @@ namespace Symfony\Component\Messenger\Exception;
*
* @author Tobias Nyholm
*/
-class DelayedMessageHandlingException extends \RuntimeException implements ExceptionInterface
+class DelayedMessageHandlingException extends RuntimeException
{
private $exceptions;
diff --git a/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php b/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php
index 9e429ecc9b..f908d42b5e 100644
--- a/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php
+++ b/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Messenger\Exception;
*
* @experimental in 4.3
*/
-class MessageDecodingFailedException extends \InvalidArgumentException implements ExceptionInterface
+class MessageDecodingFailedException extends InvalidArgumentException
{
}
diff --git a/src/Symfony/Component/Messenger/Exception/NoHandlerForMessageException.php b/src/Symfony/Component/Messenger/Exception/NoHandlerForMessageException.php
index a3fc0fa414..1e8e674d6a 100644
--- a/src/Symfony/Component/Messenger/Exception/NoHandlerForMessageException.php
+++ b/src/Symfony/Component/Messenger/Exception/NoHandlerForMessageException.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Messenger\Exception;
*
* @experimental in 4.3
*/
-class NoHandlerForMessageException extends \LogicException implements ExceptionInterface
+class NoHandlerForMessageException extends LogicException
{
}
diff --git a/src/Symfony/Component/Messenger/Exception/UnknownSenderException.php b/src/Symfony/Component/Messenger/Exception/UnknownSenderException.php
index 72fccfa566..ec138c1e20 100644
--- a/src/Symfony/Component/Messenger/Exception/UnknownSenderException.php
+++ b/src/Symfony/Component/Messenger/Exception/UnknownSenderException.php
@@ -16,6 +16,6 @@ namespace Symfony\Component\Messenger\Exception;
*
* @experimental in 4.3
*/
-class UnknownSenderException extends \InvalidArgumentException implements ExceptionInterface
+class UnknownSenderException extends InvalidArgumentException
{
}
diff --git a/src/Symfony/Component/Messenger/Exception/UnrecoverableExceptionInterface.php b/src/Symfony/Component/Messenger/Exception/UnrecoverableExceptionInterface.php
new file mode 100644
index 0000000000..d5dd01dbaa
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Exception/UnrecoverableExceptionInterface.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Exception;
+
+/**
+ * Marker interface for exceptions to indicate that handling a message will continue to fail.
+ *
+ * If something goes wrong while handling a message that's received from a transport
+ * and the message should not be retried, a handler can throw such an exception.
+ *
+ * @author Tobias Schultze
+ *
+ * @experimental in 4.3
+ */
+interface UnrecoverableExceptionInterface extends \Throwable
+{
+}
diff --git a/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php b/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php
index df08e79d8b..3a5e52be21 100644
--- a/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php
+++ b/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php
@@ -12,15 +12,12 @@
namespace Symfony\Component\Messenger\Exception;
/**
- * Thrown while handling a message to indicate that handling will continue to fail.
- *
- * If something goes wrong while handling a message that's received from a transport
- * and the message should not be retried, a handler can throw this exception.
+ * A concrete implementation of UnrecoverableExceptionInterface that can be used directly.
*
* @author Frederic Bouchery
*
* @experimental in 4.3
*/
-class UnrecoverableMessageHandlingException extends RuntimeException
+class UnrecoverableMessageHandlingException extends RuntimeException implements UnrecoverableExceptionInterface
{
}
diff --git a/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php b/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php
index a05a213526..da87bcd2a0 100644
--- a/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php
+++ b/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php
@@ -18,7 +18,7 @@ use Symfony\Component\Validator\ConstraintViolationListInterface;
*
* @experimental in 4.3
*/
-class ValidationFailedException extends \RuntimeException implements ExceptionInterface
+class ValidationFailedException extends RuntimeException
{
private $violations;
private $violatingMessage;
diff --git a/src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php b/src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php
index 4c098c79b7..19c714d1b8 100644
--- a/src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php
+++ b/src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php
@@ -112,7 +112,7 @@ final class QueuedEnvelope
public function __construct(Envelope $envelope, StackInterface $stack)
{
- $this->envelope = $envelope;
+ $this->envelope = $envelope->withoutAll(DispatchAfterCurrentBusStamp::class);
$this->stack = $stack;
}
diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php
index f2217affda..fe6d190c10 100644
--- a/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php
@@ -99,6 +99,53 @@ class DispatchAfterCurrentBusMiddlewareTest extends TestCase
$messageBus->dispatch($message);
}
+ public function testHandleDelayedEventFromQueue()
+ {
+ $message = new DummyMessage('Hello');
+ $event = new DummyEvent('Event on queue');
+
+ $middleware = new DispatchAfterCurrentBusMiddleware();
+ $commandHandlingMiddleware = $this->createMock(MiddlewareInterface::class);
+ $eventHandlingMiddleware = $this->createMock(MiddlewareInterface::class);
+
+ // This bus simulates the bus that are used when messages come back form the queue
+ $messageBusAfterQueue = new MessageBus([
+ // Create a new middleware
+ new DispatchAfterCurrentBusMiddleware(),
+ $eventHandlingMiddleware,
+ ]);
+
+ $fakePutMessageOnQueue = $this->createMock(MiddlewareInterface::class);
+ $fakePutMessageOnQueue->expects($this->any())
+ ->method('handle')
+ ->with($this->callback(function ($envelope) use ($messageBusAfterQueue) {
+ // Fake putting the message on the queue
+ // Fake reading the queue
+ // Now, we add the message back to a new bus.
+ $messageBusAfterQueue->dispatch($envelope);
+
+ return true;
+ }))
+ ->willReturnArgument(0);
+
+ $eventBus = new MessageBus([
+ $middleware,
+ $fakePutMessageOnQueue,
+ ]);
+
+ $messageBus = new MessageBus([
+ $middleware,
+ new DispatchingMiddleware($eventBus, [
+ new Envelope($event, [new DispatchAfterCurrentBusStamp()]),
+ ]),
+ $commandHandlingMiddleware,
+ ]);
+
+ $this->expectHandledMessage($commandHandlingMiddleware, 0, $message);
+ $this->expectHandledMessage($eventHandlingMiddleware, 0, $event);
+ $messageBus->dispatch($message);
+ }
+
/**
* @param MiddlewareInterface|MockObject $handlingMiddleware
*/
diff --git a/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php
index 64ff20bae3..2447a0c82b 100644
--- a/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php
+++ b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php
@@ -34,9 +34,9 @@ class RetryIntegrationTest extends TestCase
$senderAndReceiver = new DummySenderAndReceiver();
$senderLocator = $this->createMock(ContainerInterface::class);
- $senderLocator->method('has')->with('sender_alias')->willReturn(true);
- $senderLocator->method('get')->with('sender_alias')->willReturn($senderAndReceiver);
- $senderLocator = new SendersLocator([DummyMessage::class => ['sender_alias']], $senderLocator);
+ $senderLocator->method('has')->with('transportName')->willReturn(true);
+ $senderLocator->method('get')->with('transportName')->willReturn($senderAndReceiver);
+ $senderLocator = new SendersLocator([DummyMessage::class => ['transportName']], $senderLocator);
$handler = new DummyMessageHandlerFailingFirstTimes(0);
$throwingHandler = new DummyMessageHandlerFailingFirstTimes(1);
@@ -52,7 +52,7 @@ class RetryIntegrationTest extends TestCase
$envelope = new Envelope(new DummyMessage('API'));
$bus->dispatch($envelope);
- $worker = new Worker(['receiverName' => $senderAndReceiver], $bus, ['receiverName' => new MultiplierRetryStrategy()]);
+ $worker = new Worker(['transportName' => $senderAndReceiver], $bus, ['transportName' => new MultiplierRetryStrategy()]);
$worker->run([], function (?Envelope $envelope) use ($worker) {
if (null === $envelope) {
$worker->stop();
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
index 9393e210b7..83708c5085 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
@@ -230,4 +230,90 @@ class ConnectionTest extends TestCase
{
Connection::buildConfiguration('doctrine://default?new_option=woops');
}
+
+ public function testFind()
+ {
+ $queryBuilder = $this->getQueryBuilderMock();
+ $driverConnection = $this->getDBALConnectionMock();
+ $schemaSynchronizer = $this->getSchemaSynchronizerMock();
+ $id = 1;
+ $stmt = $this->getStatementMock([
+ 'id' => $id,
+ 'body' => '{"message":"Hi"}',
+ 'headers' => json_encode(['type' => DummyMessage::class]),
+ ]);
+
+ $driverConnection
+ ->method('createQueryBuilder')
+ ->willReturn($queryBuilder);
+ $queryBuilder
+ ->method('where')
+ ->willReturn($queryBuilder);
+ $queryBuilder
+ ->method('getSQL')
+ ->willReturn('');
+ $queryBuilder
+ ->method('getParameters')
+ ->willReturn([]);
+ $driverConnection
+ ->method('prepare')
+ ->willReturn($stmt);
+
+ $connection = new Connection([], $driverConnection, $schemaSynchronizer);
+ $doctrineEnvelope = $connection->find($id);
+ $this->assertEquals(1, $doctrineEnvelope['id']);
+ $this->assertEquals('{"message":"Hi"}', $doctrineEnvelope['body']);
+ $this->assertEquals(['type' => DummyMessage::class], $doctrineEnvelope['headers']);
+ }
+
+ public function testFindAll()
+ {
+ $queryBuilder = $this->getQueryBuilderMock();
+ $driverConnection = $this->getDBALConnectionMock();
+ $schemaSynchronizer = $this->getSchemaSynchronizerMock();
+ $message1 = [
+ 'id' => 1,
+ 'body' => '{"message":"Hi"}',
+ 'headers' => json_encode(['type' => DummyMessage::class]),
+ ];
+ $message2 = [
+ 'id' => 2,
+ 'body' => '{"message":"Hi again"}',
+ 'headers' => json_encode(['type' => DummyMessage::class]),
+ ];
+
+ $stmt = $this->getMockBuilder(Statement::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $stmt->expects($this->once())
+ ->method('fetchAll')
+ ->willReturn([$message1, $message2]);
+
+ $driverConnection
+ ->method('createQueryBuilder')
+ ->willReturn($queryBuilder);
+ $queryBuilder
+ ->method('where')
+ ->willReturn($queryBuilder);
+ $queryBuilder
+ ->method('getSQL')
+ ->willReturn('');
+ $queryBuilder
+ ->method('getParameters')
+ ->willReturn([]);
+ $driverConnection
+ ->method('prepare')
+ ->willReturn($stmt);
+
+ $connection = new Connection([], $driverConnection, $schemaSynchronizer);
+ $doctrineEnvelopes = $connection->findAll();
+
+ $this->assertEquals(1, $doctrineEnvelopes[0]['id']);
+ $this->assertEquals('{"message":"Hi"}', $doctrineEnvelopes[0]['body']);
+ $this->assertEquals(['type' => DummyMessage::class], $doctrineEnvelopes[0]['headers']);
+
+ $this->assertEquals(2, $doctrineEnvelopes[1]['id']);
+ $this->assertEquals('{"message":"Hi again"}', $doctrineEnvelopes[1]['body']);
+ $this->assertEquals(['type' => DummyMessage::class], $doctrineEnvelopes[1]['headers']);
+ }
}
diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php
index 46e8149f6c..c82652fe1d 100644
--- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php
+++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php
@@ -84,7 +84,7 @@ class WorkerTest extends TestCase
public function testDispatchCausesRetry()
{
$receiver = new DummyReceiver([
- [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'sender_alias')])],
+ [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'transport1')])],
]);
$bus = $this->getMockBuilder(MessageBusInterface::class)->getMock();
@@ -97,7 +97,7 @@ class WorkerTest extends TestCase
$this->assertNotNull($redeliveryStamp);
// retry count now at 1
$this->assertSame(1, $redeliveryStamp->getRetryCount());
- $this->assertSame('sender_alias', $redeliveryStamp->getSenderClassOrAlias());
+ $this->assertSame('transport1', $redeliveryStamp->getSenderClassOrAlias());
// received stamp is removed
$this->assertNull($envelope->last(ReceivedStamp::class));
@@ -108,7 +108,7 @@ class WorkerTest extends TestCase
$retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock();
$retryStrategy->expects($this->once())->method('isRetryable')->willReturn(true);
- $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]);
+ $worker = new Worker(['transport1' => $receiver], $bus, ['transport1' => $retryStrategy]);
$worker->run([], function (?Envelope $envelope) use ($worker) {
// stop after the messages finish
if (null === $envelope) {
@@ -123,7 +123,7 @@ class WorkerTest extends TestCase
public function testDispatchCausesRejectWhenNoRetry()
{
$receiver = new DummyReceiver([
- [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'sender_alias')])],
+ [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'transport1')])],
]);
$bus = $this->getMockBuilder(MessageBusInterface::class)->getMock();
@@ -132,7 +132,7 @@ class WorkerTest extends TestCase
$retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock();
$retryStrategy->expects($this->once())->method('isRetryable')->willReturn(false);
- $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]);
+ $worker = new Worker(['transport1' => $receiver], $bus, ['transport1' => $retryStrategy]);
$worker->run([], function (?Envelope $envelope) use ($worker) {
// stop after the messages finish
if (null === $envelope) {
@@ -155,7 +155,7 @@ class WorkerTest extends TestCase
$retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock();
$retryStrategy->expects($this->never())->method('isRetryable');
- $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]);
+ $worker = new Worker(['transport1' => $receiver], $bus, ['transport1' => $retryStrategy]);
$worker->run([], function (?Envelope $envelope) use ($worker) {
// stop after the messages finish
if (null === $envelope) {
diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
index 5b3a31c9ec..74a85bbfbe 100644
--- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
@@ -155,7 +155,7 @@ class Connection
return null;
}
- $doctrineEnvelope['headers'] = json_decode($doctrineEnvelope['headers'], true);
+ $doctrineEnvelope = $this->decodeEnvelopeHeaders($doctrineEnvelope);
$queryBuilder = $this->driverConnection->createQueryBuilder()
->update($this->configuration['table_name'])
@@ -238,7 +238,11 @@ class Connection
$queryBuilder->setMaxResults($limit);
}
- return $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters())->fetchAll();
+ $data = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters())->fetchAll();
+
+ return array_map(function ($doctrineEnvelope) {
+ return $this->decodeEnvelopeHeaders($doctrineEnvelope);
+ }, $data);
}
public function find($id): ?array
@@ -254,7 +258,7 @@ class Connection
'id' => $id,
])->fetch();
- return false === $data ? null : $data;
+ return false === $data ? null : $this->decodeEnvelopeHeaders($data);
}
private function createAvailableMessagesQueryBuilder(): QueryBuilder
@@ -332,4 +336,11 @@ class Connection
{
return $dateTime->format('Y-m-d\TH:i:s');
}
+
+ private function decodeEnvelopeHeaders(array $doctrineEnvelope): array
+ {
+ $doctrineEnvelope['headers'] = json_decode($doctrineEnvelope['headers'], true);
+
+ return $doctrineEnvelope;
+ }
}
diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php
index b54382bd71..a51cd3506f 100644
--- a/src/Symfony/Component/Messenger/Worker.php
+++ b/src/Symfony/Component/Messenger/Worker.php
@@ -17,13 +17,11 @@ use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
use Symfony\Component\Messenger\Event\WorkerStoppedEvent;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
-use Symfony\Component\Messenger\Exception\LogicException;
-use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
+use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface;
use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
use Symfony\Component\Messenger\Stamp\DelayStamp;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
-use Symfony\Component\Messenger\Stamp\SentStamp;
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
@@ -150,7 +148,7 @@ class Worker implements WorkerInterface
// add the delay and retry stamp info + remove ReceivedStamp
$retryEnvelope = $envelope->with(new DelayStamp($delay))
- ->with(new RedeliveryStamp($retryCount, $this->getSenderClassOrAlias($envelope)))
+ ->with(new RedeliveryStamp($retryCount, $transportName))
->withoutAll(ReceivedStamp::class);
// re-send the message
@@ -193,32 +191,10 @@ class Worker implements WorkerInterface
private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInterface $retryStrategy): bool
{
- if ($e instanceof UnrecoverableMessageHandlingException) {
- return false;
- }
-
- $sentStamp = $envelope->last(SentStamp::class);
- if (null === $sentStamp) {
- if (null !== $this->logger) {
- $this->logger->warning('Message will not be retried because the SentStamp is missing and so the target sender cannot be determined.');
- }
-
+ if ($e instanceof UnrecoverableExceptionInterface) {
return false;
}
return $retryStrategy->isRetryable($envelope);
}
-
- private function getSenderClassOrAlias(Envelope $envelope): string
- {
- /** @var SentStamp|null $sentStamp */
- $sentStamp = $envelope->last(SentStamp::class);
-
- if (null === $sentStamp) {
- // should not happen, because of the check in shouldRetry()
- throw new LogicException('Could not find SentStamp.');
- }
-
- return $sentStamp->getSenderAlias() ?: $sentStamp->getSenderClass();
- }
}
diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php
index 5731cf4458..0eb9f63a54 100644
--- a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php
@@ -24,13 +24,6 @@ class PropertyInfoCacheExtractor implements PropertyInfoExtractorInterface, Prop
{
private $propertyInfoExtractor;
private $cacheItemPool;
-
- /**
- * A cache of property information, first keyed by the method called and
- * then by the serialized method arguments.
- *
- * @var array
- */
private $arrayCache = [];
public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, CacheItemPoolInterface $cacheItemPool)
@@ -110,34 +103,22 @@ class PropertyInfoCacheExtractor implements PropertyInfoExtractorInterface, Prop
}
// Calling rawurlencode escapes special characters not allowed in PSR-6's keys
- $encodedMethod = rawurlencode($method);
- if (\array_key_exists($encodedMethod, $this->arrayCache) && \array_key_exists($serializedArguments, $this->arrayCache[$encodedMethod])) {
- return $this->arrayCache[$encodedMethod][$serializedArguments];
+ $key = rawurlencode($method.'.'.$serializedArguments);
+
+ if (\array_key_exists($key, $this->arrayCache)) {
+ return $this->arrayCache[$key];
}
- $item = $this->cacheItemPool->getItem($encodedMethod);
+ $item = $this->cacheItemPool->getItem($key);
- $data = $item->get();
if ($item->isHit()) {
- $this->arrayCache[$encodedMethod] = $data[$encodedMethod];
- // Only match if the specific arguments have been cached.
- if (\array_key_exists($serializedArguments, $data[$encodedMethod])) {
- return $this->arrayCache[$encodedMethod][$serializedArguments];
- }
- }
-
- // It's possible that the method has been called, but with different
- // arguments, in which case $data will already be initialized.
- if (!$data) {
- $data = [];
+ return $this->arrayCache[$key] = $item->get();
}
$value = $this->propertyInfoExtractor->{$method}(...$arguments);
- $data[$encodedMethod][$serializedArguments] = $value;
- $this->arrayCache[$encodedMethod][$serializedArguments] = $value;
- $item->set($data);
+ $item->set($value);
$this->cacheItemPool->save($item);
- return $this->arrayCache[$encodedMethod][$serializedArguments];
+ return $this->arrayCache[$key] = $value;
}
}
diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php
index 888458ea76..4c568985e1 100644
--- a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php
@@ -51,10 +51,6 @@ class Argon2iPasswordEncoder extends BasePasswordEncoder implements SelfSaltingE
return true;
}
- if (class_exists('ParagonIE_Sodium_Compat') && method_exists('ParagonIE_Sodium_Compat', 'crypto_pwhash_is_available')) {
- return \ParagonIE_Sodium_Compat::crypto_pwhash_is_available();
- }
-
return \function_exists('sodium_crypto_pwhash_str') || \extension_loaded('libsodium');
}
diff --git a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
index a05eb288e5..84d87c6e24 100644
--- a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
@@ -33,8 +33,8 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
$opsLimit = $opsLimit ?? max(6, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE : 6);
$memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024);
- if (2 > $opsLimit) {
- throw new \InvalidArgumentException('$opsLimit must be 2 or greater.');
+ if (3 > $opsLimit) {
+ throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
}
if (10 * 1024 > $memLimit) {
diff --git a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
index 0cdfea718d..66a513f3d2 100644
--- a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
@@ -37,8 +37,8 @@ final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSalti
$this->opsLimit = $opsLimit ?? max(6, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE : 6);
$this->memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 2014);
- if (2 > $this->opsLimit) {
- throw new \InvalidArgumentException('$opsLimit must be 2 or greater.');
+ if (3 > $this->opsLimit) {
+ throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
}
if (10 * 1024 > $this->memLimit) {
@@ -48,15 +48,7 @@ final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSalti
public static function isSupported(): bool
{
- if (\extension_loaded('libsodium') || \function_exists('sodium_crypto_pwhash_str')) {
- return true;
- }
-
- if (class_exists('ParagonIE_Sodium_Compat') && method_exists('ParagonIE_Sodium_Compat', 'crypto_pwhash_is_available')) {
- return \ParagonIE_Sodium_Compat::crypto_pwhash_is_available();
- }
-
- return false;
+ return \function_exists('sodium_crypto_pwhash_str_needs_rehash') || \function_exists('Sodium\crypto_pwhash_str_needs_rehash');
}
/**
diff --git a/src/Symfony/Component/Validator/Constraints/AbstractComparison.php b/src/Symfony/Component/Validator/Constraints/AbstractComparison.php
index 89c2690c08..435ced6eb8 100644
--- a/src/Symfony/Component/Validator/Constraints/AbstractComparison.php
+++ b/src/Symfony/Component/Validator/Constraints/AbstractComparison.php
@@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
+use Symfony\Component\Validator\Exception\LogicException;
/**
* Used for the comparison of values.
@@ -46,7 +47,7 @@ abstract class AbstractComparison extends Constraint
}
if (isset($options['propertyPath']) && !class_exists(PropertyAccess::class)) {
- throw new ConstraintDefinitionException(sprintf('The "%s" constraint requires the Symfony PropertyAccess component to use the "propertyPath" option.', \get_class($this)));
+ throw new LogicException(sprintf('The "%s" constraint requires the Symfony PropertyAccess component to use the "propertyPath" option.', \get_class($this)));
}
}
diff --git a/src/Symfony/Component/VarExporter/README.md b/src/Symfony/Component/VarExporter/README.md
index 180554ed1a..bb13960e0d 100644
--- a/src/Symfony/Component/VarExporter/README.md
+++ b/src/Symfony/Component/VarExporter/README.md
@@ -31,7 +31,7 @@ It also provides a few improvements over `var_export()`/`serialize()`:
Resources
---------
- * [Documentation](https://symfony.com/doc/current/components/var_exporter/introduction.html)
+ * [Documentation](https://symfony.com/doc/current/components/var_exporter.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php
index 8d1762913c..bc613868f2 100644
--- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php
+++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php
@@ -41,6 +41,17 @@ switch ($vars['REQUEST_URI']) {
ob_start('ob_gzhandler');
break;
+ case '/103':
+ header('HTTP/1.1 103 Early Hints');
+ header('Link: ; rel=preload; as=style', false);
+ header('Link: ; rel=preload; as=script', false);
+ echo "HTTP/1.1 200 OK\r\n";
+ echo "Date: Fri, 26 May 2017 10:02:11 GMT\r\n";
+ echo "Content-Length: 13\r\n";
+ echo "\r\n";
+ echo 'Here the body';
+ exit;
+
case '/404':
header('Content-Type: application/json', true, 404);
break;
diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
index c995bc26fc..c0acd55cea 100644
--- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
+++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php
@@ -721,6 +721,15 @@ abstract class HttpClientTestCase extends TestCase
$this->assertSame('/?a=a&b=b', $body['REQUEST_URI']);
}
+ public function testInformationalResponse()
+ {
+ $client = $this->getHttpClient(__FUNCTION__);
+ $response = $client->request('GET', 'http://localhost:8057/103');
+
+ $this->assertSame('Here the body', $response->getContent());
+ $this->assertSame(200, $response->getStatusCode());
+ }
+
/**
* @requires extension zlib
*/