Merge branch '4.3'

* 4.3: (22 commits)
  [Messenger] Fix incorrect error when symfony/serializer is missing
  Allow WrappedListener to describe uncallable listeners.
  [HttpClient] fix handling exceptions thrown before first mock chunk
  [Filesystem] fix wrong method call casing
  [HttpClient] fix test
  [Translation] Fixed issue with new vs old TranslatorInterface in TranslationDataCollector
  Don't reference symfony/security
  [HttpClient] display proper error message on TransportException when curl is used
  [FrameworkBundle] fix named autowiring aliases for TagAwareCacheInterface
  [Cache] improve logged messages
  [FrameworkBundle] improve cs
  [Mime][HttpFoundation] Added mime type audio/x-hx-aac-adts
  bumped Symfony version to 4.3.0
  updated VERSION for 4.3.0-BETA2
  updated CHANGELOG for 4.3.0-BETA2
  [HttpClient] Only use CURLMOPT_MAX_HOST_CONNECTIONS & CURL_VERSION_HTTP2 if defined
  [Security] fixed a fatal error when upgrading from 4.2
  [HttpClient] Allow arrays as query parameters
  Throws UnrecoverableMessageHandlingException when passed invalid entity manager name for Doctrine middlewares
  [Messenger] Make redis Connection::get() non blocking by default
  ...
This commit is contained in:
Fabien Potencier 2019-05-26 11:07:14 +02:00
commit 5dba412d30
47 changed files with 368 additions and 98 deletions

View File

@ -7,6 +7,51 @@ in 4.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1
* 4.3.0-BETA2 (2019-05-22)
* bug #31569 [HttpClient] Only use CURLMOPT_MAX_HOST_CONNECTIONS & CURL_VERSION_HTTP2 if defined (GawainLynch)
* bug #31566 [Security] fixed a fatal error when upgrading from 4.2 (fabpot)
* bug #31219 [HttpClient] Allow arrays as query parameters (sleepyboy)
* bug #31482 [Messenger][DoctrineBridge] Throws UnrecoverableMessageHandlingException when passed invalid entity manager name (Koc)
* feature #31471 [Messenger] Add "non sendable" stamps (weaverryan)
* bug #31545 [Messenger] Fix redis Connection::get() should be non blocking by default (chalasr)
* bug #31537 [Workflow] use method marking store (noniagriconomie)
* bug #31551 [ProxyManager] isProxyCandidate() does not take into account interfaces (andrerom)
* bug #31542 [HttpClient] add missing argument check (nicolas-grekas)
* bug #31544 [Messenger] Fix undefined index on read timeout (chalasr)
* bug #31335 [Doctrine] Respect parent class contract in ContainerAwareEventManager (Koc)
* bug #31421 [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name (przemyslaw-bogusz)
* bug #31493 [EventDispatcher] Removed "callable" type hint from WrappedListener constructor (wskorodecki)
* bug #31502 [WebProfilerBundle][Form] The form data collector return serialized data (Simperfit)
* bug #31510 Use the current working dir as default first arg in 'link' binary (lyrixx)
* bug #31524 [HttpFoundation] prevent deprecation when filesize matches error code (xabbuh)
* bug #31535 [Debug] Wrap call to require_once in a try/catch (lyrixx)
* feature #31030 [Serializer] Deprecate calling createChildContext without the format parameter (dbu)
* bug #31459 Fix the interface incompatibility of EventDispatchers (keulinho)
* bug #31463 [DI] default to service id - *not* FQCN - when building tagged locators (nicolas-grekas)
* feature #31294 [Form] Add intl/choice_translation_locale option to TimezoneType (ro0NL)
* feature #31452 [FrameworkBundle] Add cache configuration for PropertyInfo (alanpoulain)
* feature #31486 [Doctrine][PropertyInfo] Detect if the ID is writeable (dunglas)
* bug #31481 [Validator] Autovalidation: skip readonly props (dunglas)
* bug #31480 Update dependencies in the main component (DavidPrevot)
* bug #31477 [PropertyAccess] Add missing property to PropertyAccessor (vudaltsov)
* bug #31479 [Cache] fix saving unrelated keys in recursive callback calls (nicolas-grekas)
* bug #30930 [FrameworkBundle] Fixed issue when a parameter contains a '' (lyrixx)
* bug #31438 [Serializer] Fix denormalization of object with variadic constructor typed argument (ajgarlag)
* bug #31445 [Messenger] Making cache rebuild correctly when message subscribers change (weaverryan)
* bug #31442 [Validator] Fix finding translator parent definition in compiler pass (deguif)
* bug #31475 [HttpFoundation] Allow set 'None' on samesite cookie flag (markitosgv)
* feature #31454 [Messenger] remove send_and_handle which can be achieved with SyncTransport (Tobion)
* bug #31425 [Messenger] On failure retry, make message appear received from original sender (weaverryan)
* bug #31472 [Messenger] Fix routable message bus default bus (weaverryan)
* bug #31465 [Serializer] Fix BC break: DEPTH_KEY_PATTERN must be public (dunglas)
* bug #31458 [TwigBundle] Fix Mailer integration in Twig (fabpot)
* bug #31456 Remove deprecated usage of some Twig features (fabpot)
* bug #31207 [Routing] Fixed unexpected 404 NoConfigurationException (yceruto)
* bug #31261 [Console] Commands with an alias should not be recognized as ambiguous when using register (Simperfit)
* bug #31371 [DI] Removes number of elements information in debug mode (jschaedl)
* bug #31418 [FrameworkBundle] clarify the possible class/interface of the cache (xabbuh)
* 4.3.0-BETA1 (2019-05-09)
* feature #31249 [Translator] Set sources when extracting strings from php files (Stadly)

View File

@ -12,8 +12,8 @@
namespace Symfony\Bridge\Doctrine\Messenger;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
@ -40,10 +40,10 @@ class DoctrineCloseConnectionMiddleware implements MiddlewareInterface
*/
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
if (!$entityManager instanceof EntityManagerInterface) {
throw new \InvalidArgumentException(sprintf('The ObjectManager with name "%s" must be an instance of EntityManagerInterface', $this->entityManagerName));
try {
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
} catch (\InvalidArgumentException $e) {
throw new UnrecoverableMessageHandlingException($e->getMessage(), 0, $e);
}
try {

View File

@ -12,8 +12,8 @@
namespace Symfony\Bridge\Doctrine\Messenger;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
@ -40,10 +40,10 @@ class DoctrinePingConnectionMiddleware implements MiddlewareInterface
*/
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
if (!$entityManager instanceof EntityManagerInterface) {
throw new \InvalidArgumentException(sprintf('The ObjectManager with name "%s" must be an instance of EntityManagerInterface', $this->entityManagerName));
try {
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
} catch (\InvalidArgumentException $e) {
throw new UnrecoverableMessageHandlingException($e->getMessage(), 0, $e);
}
$connection = $entityManager->getConnection();

View File

@ -12,8 +12,8 @@
namespace Symfony\Bridge\Doctrine\Messenger;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
@ -40,10 +40,10 @@ class DoctrineTransactionMiddleware implements MiddlewareInterface
*/
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
if (!$entityManager instanceof EntityManagerInterface) {
throw new \InvalidArgumentException(sprintf('The ObjectManager with name "%s" must be an instance of EntityManagerInterface', $this->entityManagerName));
try {
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
} catch (\InvalidArgumentException $e) {
throw new UnrecoverableMessageHandlingException($e->getMessage(), 0, $e);
}
$entityManager->getConnection()->beginTransaction();

View File

@ -16,6 +16,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Messenger\DoctrineCloseConnectionMiddleware;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase;
class DoctrineCloseConnectionMiddlewareTest extends MiddlewareTestCase
@ -50,4 +51,19 @@ class DoctrineCloseConnectionMiddlewareTest extends MiddlewareTestCase
$this->middleware->handle(new Envelope(new \stdClass()), $this->getStackMock());
}
public function testInvalidEntityManagerThrowsException()
{
$managerRegistry = $this->createMock(ManagerRegistry::class);
$managerRegistry
->method('getManager')
->with('unknown_manager')
->will($this->throwException(new \InvalidArgumentException()));
$middleware = new DoctrineCloseConnectionMiddleware($managerRegistry, 'unknown_manager');
$this->expectException(UnrecoverableMessageHandlingException::class);
$middleware->handle(new Envelope(new \stdClass()), $this->getStackMock(false));
}
}

View File

@ -16,6 +16,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase;
class DoctrinePingConnectionMiddlewareTest extends MiddlewareTestCase
@ -71,4 +72,19 @@ class DoctrinePingConnectionMiddlewareTest extends MiddlewareTestCase
$this->middleware->handle(new Envelope(new \stdClass()), $this->getStackMock());
}
public function testInvalidEntityManagerThrowsException()
{
$managerRegistry = $this->createMock(ManagerRegistry::class);
$managerRegistry
->method('getManager')
->with('unknown_manager')
->will($this->throwException(new \InvalidArgumentException()));
$middleware = new DoctrinePingConnectionMiddleware($managerRegistry, 'unknown_manager');
$this->expectException(UnrecoverableMessageHandlingException::class);
$middleware->handle(new Envelope(new \stdClass()), $this->getStackMock(false));
}
}

View File

@ -16,6 +16,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase;
class DoctrineTransactionMiddlewareTest extends MiddlewareTestCase
@ -67,4 +68,19 @@ class DoctrineTransactionMiddlewareTest extends MiddlewareTestCase
$this->middleware->handle(new Envelope(new \stdClass()), $this->getThrowingStackMock());
}
public function testInvalidEntityManagerThrowsException()
{
$managerRegistry = $this->createMock(ManagerRegistry::class);
$managerRegistry
->method('getManager')
->with('unknown_manager')
->will($this->throwException(new \InvalidArgumentException()));
$middleware = new DoctrineTransactionMiddleware($managerRegistry, 'unknown_manager');
$this->expectException(UnrecoverableMessageHandlingException::class);
$middleware->handle(new Envelope(new \stdClass()), $this->getStackMock(false));
}
}

View File

@ -29,11 +29,11 @@
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/form": "~4.3",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/messenger": "~4.2",
"symfony/messenger": "~4.3",
"symfony/property-access": "~3.4|~4.0",
"symfony/property-info": "~3.4|~4.0",
"symfony/proxy-manager-bridge": "~3.4|~4.0",
"symfony/security": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/validator": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
@ -49,7 +49,7 @@
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.4",
"symfony/form": "<4.3",
"symfony/messenger": "<4.2"
"symfony/messenger": "<4.3"
},
"suggest": {
"symfony/form": "",

View File

@ -34,8 +34,9 @@
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~4.2",
"symfony/yaml": "~3.4|~4.0",
"symfony/security": "~3.4|~4.0",
"symfony/security-acl": "~2.8|~3.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/security-http": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0",
@ -59,7 +60,9 @@
"symfony/templating": "For using the TwigEngine",
"symfony/translation": "For using the TranslationExtension",
"symfony/yaml": "For using the YamlExtension",
"symfony/security": "For using the SecurityExtension",
"symfony/security-core": "For using the SecurityExtension",
"symfony/security-csrf": "For using the CsrfExtension",
"symfony/security-http": "For using the LogoutUrlExtension",
"symfony/stopwatch": "For using the StopwatchExtension",
"symfony/var-dumper": "For using the DumpExtension",
"symfony/expression-language": "For using the ExpressionExtension",

View File

@ -117,6 +117,7 @@ use Symfony\Component\Workflow\WorkflowInterface;
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
use Symfony\Component\Yaml\Yaml;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\Service\ResetInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
@ -737,7 +738,7 @@ class FrameworkExtension extends Extension
}
if (!class_exists(Security::class)) {
throw new LogicException('Cannot guard workflows as the Security component is not installed. Try running "composer require symfony/security".');
throw new LogicException('Cannot guard workflows as the Security component is not installed. Try running "composer require symfony/security-core".');
}
$guard = new Definition(Workflow\EventListener\GuardListener::class);
@ -1819,13 +1820,9 @@ class FrameworkExtension extends Extension
$pool['adapter'] = '.'.$pool['adapter'].'.inner';
}
$definition = new ChildDefinition($pool['adapter']);
if (!\in_array($name, ['cache.app', 'cache.system'], true)) {
$container->registerAliasForArgument($name, CacheInterface::class);
$container->registerAliasForArgument($name, CacheItemPoolInterface::class);
}
if ($pool['tags']) {
if ($config['pools'][$pool['tags']]['tags'] ?? false) {
if (true !== $pool['tags'] && ($config['pools'][$pool['tags']]['tags'] ?? false)) {
$pool['tags'] = '.'.$pool['tags'].'.inner';
}
$container->register($name, TagAwareAdapter::class)
@ -1837,7 +1834,21 @@ class FrameworkExtension extends Extension
$pool['name'] = $name;
$pool['public'] = false;
$name = '.'.$name.'.inner';
if (!\in_array($pool['name'], ['cache.app', 'cache.system'], true)) {
$container->registerAliasForArgument($pool['name'], TagAwareCacheInterface::class);
$container->registerAliasForArgument($name, CacheInterface::class, $pool['name']);
$container->registerAliasForArgument($name, CacheItemPoolInterface::class, $pool['name']);
}
} elseif (!\in_array($name, ['cache.app', 'cache.system'], true)) {
$container->register('.'.$name.'.taggable', TagAwareAdapter::class)
->addArgument(new Reference($name))
;
$container->registerAliasForArgument('.'.$name.'.taggable', TagAwareCacheInterface::class, $name);
$container->registerAliasForArgument($name, CacheInterface::class);
$container->registerAliasForArgument($name, CacheItemPoolInterface::class);
}
$definition->setPublic($pool['public']);
unset($pool['adapter'], $pool['public'], $pool['tags']);

View File

@ -38,7 +38,6 @@
"symfony/css-selector": "~3.4|~4.0",
"symfony/dom-crawler": "^4.3",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/security": "~3.4|~4.0",
"symfony/form": "^4.3",
"symfony/expression-language": "~3.4|~4.0",
"symfony/http-client": "^4.3",
@ -46,8 +45,8 @@
"symfony/messenger": "^4.3",
"symfony/mime": "^4.3",
"symfony/process": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/security-http": "~3.4|~4.0",
"symfony/serializer": "^4.3",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/translation": "~4.2",

View File

@ -253,7 +253,8 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]);
$message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
$ok = false;
}

View File

@ -198,7 +198,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
$info = $host->info('Server');
$info = isset($info['Server']) ? $info['Server'] : $info;
if (version_compare($info['redis_version'], '3.2', '<')) {
CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as {version}', ['version' => $info['redis_version']]);
CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as '.$info['redis_version']);
return $this->redisServerSupportSPOP = false;
}

View File

@ -56,7 +56,7 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
return $value;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
}
return $default;
@ -90,7 +90,7 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
try {
$values = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => $keys, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]);
$values = [];
}
$ids = array_combine($ids, $keys);
@ -129,7 +129,8 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) {
$keys[] = substr($id, \strlen($this->namespace));
}
CacheItem::log($this->logger, 'Failed to save values', ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]);
$message = 'Failed to save values'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]);
return false;
}
@ -175,7 +176,7 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
yield $key => $value;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => array_values($keys), 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]);
}
foreach ($keys as $key) {

View File

@ -52,7 +52,7 @@ trait AbstractAdapterTrait
$isHit = true;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
}
return $f($key, $value, $isHit);
@ -74,7 +74,7 @@ trait AbstractAdapterTrait
try {
$items = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]);
$items = [];
}
$ids = array_combine($ids, $keys);
@ -129,7 +129,7 @@ trait AbstractAdapterTrait
yield $key => $f($key, $value, true);
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]);
}
foreach ($keys as $key) {

View File

@ -94,7 +94,7 @@ trait AbstractTrait
try {
return $this->doHave($id);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', ['key' => $key, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached: '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
return false;
}
@ -122,7 +122,7 @@ trait AbstractTrait
try {
return $this->doClear($this->namespace) || $cleared;
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache', ['exception' => $e]);
CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);
return false;
}
@ -166,7 +166,8 @@ trait AbstractTrait
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]);
$message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
$ok = false;
}

View File

@ -128,8 +128,8 @@ trait ArrayTrait
$serialized = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
$message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.');
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]);
$message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage());
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e]);
return;
}
@ -151,7 +151,7 @@ trait ArrayTrait
try {
$value = unserialize($value);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]);
CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
$value = false;
}
if (false === $value) {

View File

@ -41,7 +41,7 @@ class WrappedListener
public function __construct($listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
{
$this->listener = $listener;
$this->optimizedListener = $listener instanceof \Closure ? $listener : \Closure::fromCallable($listener);
$this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null);
$this->stopwatch = $stopwatch;
$this->dispatcher = $dispatcher;
$this->called = false;
@ -123,7 +123,7 @@ class WrappedListener
$e = $this->stopwatch->start($this->name, 'event_listener');
($this->optimizedListener)($event, $eventName, $dispatcher);
($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);
if ($e->isStarted()) {
$e->stop();

View File

@ -21,7 +21,7 @@ class WrappedListenerTest extends TestCase
/**
* @dataProvider provideListenersToDescribe
*/
public function testListenerDescription(callable $listener, $expected)
public function testListenerDescription($listener, $expected)
{
$wrappedListener = new WrappedListener($listener, null, $this->getMockBuilder(Stopwatch::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock());
@ -34,6 +34,7 @@ class WrappedListenerTest extends TestCase
[new FooListener(), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::__invoke'],
[[new FooListener(), 'listen'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'],
[['Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'listenStatic'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listenStatic'],
[['Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'invalidMethod'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::invalidMethod'],
['var_dump', 'var_dump'],
[function () {}, 'closure'],
[\Closure::fromCallable([new FooListener(), 'listen']), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'],

View File

@ -572,7 +572,7 @@ class Filesystem
$targetDirInfo = new \SplFileInfo($targetDir);
foreach ($iterator as $file) {
if ($file->getPathName() === $targetDir || $file->getRealPath() === $targetDir || 0 === strpos($file->getRealPath(), $targetDirInfo->getRealPath())) {
if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || 0 === strpos($file->getRealPath(), $targetDirInfo->getRealPath())) {
continue;
}

View File

@ -70,7 +70,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
if (\defined('CURLPIPE_MULTIPLEX')) {
curl_multi_setopt($this->multi->handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
}
curl_multi_setopt($this->multi->handle, CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX);
if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) {
curl_multi_setopt($this->multi->handle, CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX);
}
// Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/bug.php?id=77535
if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) {
@ -188,7 +190,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface
$curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
} elseif (1.1 === (float) $options['http_version'] || 'https:' !== $scheme) {
$curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
} elseif (CURL_VERSION_HTTP2 & curl_version()['features']) {
} elseif (\defined('CURL_VERSION_HTTP2') && CURL_VERSION_HTTP2 & curl_version()['features']) {
$curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
}

View File

@ -27,7 +27,7 @@ trait HttpExceptionTrait
$this->response = $response;
$code = $response->getInfo('http_code');
$url = $response->getInfo('url');
$message = sprintf('HTTP %d returned for URL "%s".', $code, $url);
$message = sprintf('HTTP %d returned for "%s".', $code, $url);
$httpCodeFound = false;
$isJson = false;
@ -37,7 +37,7 @@ trait HttpExceptionTrait
break;
}
$message = sprintf('%s returned for URL "%s".', $h, $url);
$message = sprintf('%s returned for "%s".', $h, $url);
$httpCodeFound = true;
}

View File

@ -481,17 +481,20 @@ trait HttpClientTrait
}
}
foreach ($queryArray as $k => $v) {
if (is_scalar($v)) {
$queryArray[$k] = rawurlencode($k).'='.rawurlencode($v);
} elseif (null === $v) {
unset($queryArray[$k]);
if ($replace) {
if ($replace) {
foreach ($queryArray as $k => $v) {
if (null === $v) {
unset($query[$k]);
}
} else {
throw new InvalidArgumentException(sprintf('Unsupported value for query parameter "%s": scalar or null expected, %s given.', $k, \gettype($v)));
}
}
$queryString = http_build_query($queryArray, '', '&', PHP_QUERY_RFC3986);
$queryArray = [];
if ($queryString) {
foreach (explode('&', $queryString) as $v) {
$queryArray[rawurldecode(explode('=', $v, 2)[0])] = $v;
}
}

View File

@ -245,7 +245,7 @@ final class CurlResponse implements ResponseInterface
while ($info = curl_multi_info_read($multi->handle)) {
$multi->handlesActivity[(int) $info['handle']][] = null;
$multi->handlesActivity[(int) $info['handle']][] = \in_array($info['result'], [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || (\CURLE_WRITE_ERROR === $info['result'] && 'destruct' === @curl_getinfo($info['handle'], CURLINFO_PRIVATE)) ? null : new TransportException(curl_error($info['handle']));
$multi->handlesActivity[(int) $info['handle']][] = \in_array($info['result'], [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || (\CURLE_WRITE_ERROR === $info['result'] && 'destruct' === @curl_getinfo($info['handle'], CURLINFO_PRIVATE)) ? null : new TransportException(sprintf('%s for"%s".', curl_strerror($info['result']), curl_getinfo($info['handle'], CURLINFO_EFFECTIVE_URL)));
}
} finally {
self::$performing = false;

View File

@ -25,7 +25,9 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
*/
class MockResponse implements ResponseInterface
{
use ResponseTrait;
use ResponseTrait {
doDestruct as public __destruct;
}
private $body;
private $requestOptions = [];
@ -162,8 +164,8 @@ class MockResponse implements ResponseInterface
$offset = 0;
$chunk[1]->getStatusCode();
$response->headers = $chunk[1]->getHeaders(false);
$multi->handlesActivity[$id][] = new FirstChunk();
self::readResponse($response, $chunk[0], $chunk[1], $offset);
$multi->handlesActivity[$id][] = new FirstChunk();
} catch (\Throwable $e) {
$multi->handlesActivity[$id][] = null;
$multi->handlesActivity[$id][] = $e;

View File

@ -61,14 +61,14 @@ class CurlHttpClientTest extends HttpClientTestCase
$js->getHeaders();
$expected = [
'Request: GET https://http2-push.io/',
'Queueing pushed response: https://http2-push.io/css/style.css',
'Queueing pushed response: https://http2-push.io/js/http2-push.js',
'Response: 200 https://http2-push.io/',
'Connecting request to pushed response: GET https://http2-push.io/css/style.css',
'Connecting request to pushed response: GET https://http2-push.io/js/http2-push.js',
'Response: 200 https://http2-push.io/css/style.css',
'Response: 200 https://http2-push.io/js/http2-push.js',
'Request: "GET https://http2-push.io/"',
'Queueing pushed response: "https://http2-push.io/css/style.css"',
'Queueing pushed response: "https://http2-push.io/js/http2-push.js"',
'Response: "200 https://http2-push.io/"',
'Connecting request to pushed response: "GET https://http2-push.io/css/style.css"',
'Connecting request to pushed response: "GET https://http2-push.io/js/http2-push.js"',
'Response: "200 https://http2-push.io/css/style.css"',
'Response: "200 https://http2-push.io/js/http2-push.js"',
];
$this->assertSame($expected, $logger->logs);
}

View File

@ -141,6 +141,10 @@ class HttpClientTraitTest extends TestCase
yield [[null, null, 'bar', '?a=1&c=c', null], 'bar?a=a&b=b', ['b' => null, 'c' => 'c', 'a' => 1]];
yield [[null, null, 'bar', '?a=b+c&b=b', null], 'bar?a=b+c', ['b' => 'b']];
yield [[null, null, 'bar', '?a=b%2B%20c', null], 'bar?a=b+c', ['a' => 'b+ c']];
yield [[null, null, 'bar', '?a%5Bb%5D=c', null], 'bar', ['a' => ['b' => 'c']]];
yield [[null, null, 'bar', '?a%5Bb%5Bc%5D=d', null], 'bar?a[b[c]=d', []];
yield [[null, null, 'bar', '?a%5Bb%5D%5Bc%5D=dd', null], 'bar?a[b][c]=d&e[f]=g', ['a' => ['b' => ['c' => 'dd']], 'e[f]' => null]];
yield [[null, null, 'bar', '?a=b&a%5Bb%20c%5D=d&e%3Df=%E2%9C%93', null], 'bar?a=b', ['a' => ['b c' => 'd'], 'e=f' => '✓']];
}
/**

View File

@ -115,7 +115,7 @@ class MockHttpClientTest extends HttpClientTestCase
case 'testResolve':
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
$responses[] = $client->request('GET', 'http://symfony.com:8057/');
$responses[] = new MockResponse((function () { throw new \Exception('Fake connection timeout'); yield ''; })(), ['response_headers' => $headers]);
break;
case 'testTimeoutOnStream':

View File

@ -645,6 +645,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface
'audio/x-aiff' => 'aif',
'audio/x-caf' => 'caf',
'audio/x-flac' => 'flac',
'audio/x-hx-aac-adts' => 'aac',
'audio/x-matroska' => 'mka',
'audio/x-mpegurl' => 'm3u',
'audio/x-ms-wax' => 'wax',

View File

@ -17,6 +17,22 @@ use Symfony\Component\Ldap\Entry;
class EntryManagerTest extends TestCase
{
/**
* @expectedException \Symfony\Component\Ldap\Exception\LdapException
* @expectedExceptionMessage Entry "$$$$$$" malformed, could not parse RDN.
*/
public function testMove()
{
$connection = $this->createMock(Connection::class);
$connection
->expects($this->once())
->method('isBound')->willReturn(true);
$entry = new Entry('$$$$$$');
$entryManager = new EntryManager($connection);
$entryManager->move($entry, 'a');
}
/**
* @expectedException \Symfony\Component\Ldap\Exception\NotBoundException
* @expectedExceptionMessage Query execution is not possible without binding the connection first.

View File

@ -4,6 +4,9 @@ CHANGELOG
4.3.0
-----
* Added `NonSendableStampInterface` that a stamp can implement if
it should not be sent to a transport. Transport serializers
must now check for these stamps and not encode them.
* [BC BREAK] `SendersLocatorInterface` has an additional method:
`getSenderByAlias()`.
* Removed argument `?bool &$handle = false` from `SendersLocatorInterface::getSenders`

View File

@ -80,6 +80,22 @@ final class Envelope
return $cloned;
}
/**
* Removes all stamps that implement the given type.
*/
public function withoutStampsOfType(string $type): self
{
$cloned = clone $this;
foreach ($cloned->stamps as $class => $stamps) {
if ($class === $type || \is_subclass_of($class, $type)) {
unset($cloned->stamps[$class]);
}
}
return $cloned;
}
public function last(string $stampFqcn): ?StampInterface
{
return isset($this->stamps[$stampFqcn]) ? end($this->stamps[$stampFqcn]) : null;

View File

@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Messenger\Stamp;
/**
* A stamp that should not be included with the Envelope if sent to a transport.
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*
* @experimental in 4.3
*/
interface NonSendableStampInterface extends StampInterface
{
}

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Stamp\DelayStamp;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
use Symfony\Component\Messenger\Stamp\StampInterface;
use Symfony\Component\Messenger\Stamp\ValidationStamp;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@ -50,6 +51,30 @@ class EnvelopeTest extends TestCase
$this->assertCount(1, $envelope->all(DelayStamp::class));
}
public function testWithoutStampsOfType()
{
$envelope = new Envelope(new DummyMessage('dummy'), [
new ReceivedStamp('transport1'),
new DelayStamp(5000),
new DummyExtendsDelayStamp(5000),
new DummyImplementsFooBarStampInterface(),
]);
$envelope2 = $envelope->withoutStampsOfType(DummyNothingImplementsMeStampInterface::class);
$this->assertEquals($envelope, $envelope2);
$envelope3 = $envelope2->withoutStampsOfType(ReceivedStamp::class);
$this->assertEmpty($envelope3->all(ReceivedStamp::class));
$envelope4 = $envelope3->withoutStampsOfType(DelayStamp::class);
$this->assertEmpty($envelope4->all(DelayStamp::class));
$this->assertEmpty($envelope4->all(DummyExtendsDelayStamp::class));
$envelope5 = $envelope4->withoutStampsOfType(DummyFooBarStampInterface::class);
$this->assertEmpty($envelope5->all(DummyImplementsFooBarStampInterface::class));
$this->assertEmpty($envelope5->all());
}
public function testLast()
{
$receivedStamp = new ReceivedStamp('transport');
@ -92,3 +117,16 @@ class EnvelopeTest extends TestCase
$this->assertCount(1, $envelope->all(ReceivedStamp::class));
}
}
class DummyExtendsDelayStamp extends DelayStamp
{
}
interface DummyFooBarStampInterface extends StampInterface
{
}
interface DummyNothingImplementsMeStampInterface extends StampInterface
{
}
class DummyImplementsFooBarStampInterface implements DummyFooBarStampInterface
{
}

View File

@ -46,9 +46,9 @@ class ConnectionTest extends TestCase
'host' => 'localhost',
'port' => 6379,
], [
'blocking_timeout' => 30,
'serializer' => 2,
]),
Connection::fromDsn('redis://localhost/queue/group1/consumer1', ['blocking_timeout' => 30])
Connection::fromDsn('redis://localhost/queue/group1/consumer1', ['serializer' => 2])
);
}
@ -59,9 +59,9 @@ class ConnectionTest extends TestCase
'host' => 'localhost',
'port' => 6379,
], [
'blocking_timeout' => 30,
'serializer' => 2,
]),
Connection::fromDsn('redis://localhost/queue/group1/consumer1?blocking_timeout=30')
Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2')
);
}
@ -134,16 +134,20 @@ class ConnectionTest extends TestCase
$redis->del('messenger-rejectthenget');
}
public function testBlockingTimeout()
public function testGetNonBlocking()
{
$redis = new \Redis();
$connection = Connection::fromDsn('redis://localhost/messenger-blockingtimeout', ['blocking_timeout' => 1], $redis);
$connection = Connection::fromDsn('redis://localhost/messenger-getnonblocking', [], $redis);
try {
$connection->setup();
} catch (TransportException $e) {
}
$this->assertNull($connection->get());
$redis->del('messenger-blockingtimeout');
$this->assertNull($connection->get()); // no message, should return null immediately
$connection->add('1', []);
$this->assertNotEmpty($message = $connection->get());
$connection->reject($message['id']);
$redis->del('messenger-getnonblocking');
}
}

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Serialization;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer;
@ -63,4 +64,20 @@ class PhpSerializerTest extends TestCase
'body' => 'O:13:"ReceivedSt0mp":0:{}',
]);
}
public function testEncodedSkipsNonEncodeableStamps()
{
$serializer = new PhpSerializer();
$envelope = new Envelope(new DummyMessage('Hello'), [
new DummyPhpSerializerNonSendableStamp(),
]);
$encoded = $serializer->encode($envelope);
$this->assertNotContains('DummyPhpSerializerNonSendableStamp', $encoded['body']);
}
}
class DummyPhpSerializerNonSendableStamp implements NonSendableStampInterface
{
}

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Serialization;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
use Symfony\Component\Messenger\Stamp\SerializerStamp;
use Symfony\Component\Messenger\Stamp\ValidationStamp;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@ -193,4 +194,19 @@ class SerializerTest extends TestCase
'headers' => ['type' => 'NonExistentClass'],
]);
}
public function testEncodedSkipsNonEncodeableStamps()
{
$serializer = new Serializer();
$envelope = new Envelope(new DummyMessage('Hello'), [
new DummySymfonySerializerNonSendableStamp(),
]);
$encoded = $serializer->encode($envelope);
$this->assertNotContains('DummySymfonySerializerNonSendableStamp', print_r($encoded['headers'], true));
}
}
class DummySymfonySerializerNonSendableStamp implements NonSendableStampInterface
{
}

View File

@ -11,14 +11,14 @@
namespace Symfony\Component\Messenger\Transport\AmqpExt;
use Symfony\Component\Messenger\Stamp\StampInterface;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
/**
* Stamp applied when a message is received from Amqp.
*
* @experimental in 4.3
*/
class AmqpReceivedStamp implements StampInterface
class AmqpReceivedStamp implements NonSendableStampInterface
{
private $amqpEnvelope;
private $queueName;

View File

@ -11,14 +11,14 @@
namespace Symfony\Component\Messenger\Transport\Doctrine;
use Symfony\Component\Messenger\Stamp\StampInterface;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
/**
* @author Vincent Touzet <vincent.touzet@gmail.com>
*
* @experimental in 4.3
*/
class DoctrineReceivedStamp implements StampInterface
class DoctrineReceivedStamp implements NonSendableStampInterface
{
private $id;

View File

@ -31,7 +31,6 @@ class Connection
private $stream;
private $group;
private $consumer;
private $blockingTimeout;
private $couldHavePendingMessages = true;
public function __construct(array $configuration, array $connectionCredentials = [], array $redisOptions = [], \Redis $redis = null)
@ -42,7 +41,6 @@ class Connection
$this->stream = $configuration['stream'] ?? '' ?: 'messages';
$this->group = $configuration['group'] ?? '' ?: 'symfony';
$this->consumer = $configuration['consumer'] ?? '' ?: 'consumer';
$this->blockingTimeout = $redisOptions['blocking_timeout'] ?? null;
}
public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $redis = null): self
@ -83,8 +81,7 @@ class Connection
$this->group,
$this->consumer,
[$this->stream => $messageId],
1,
$this->blockingTimeout
1
);
} catch (\RedisException $e) {
}
@ -142,7 +139,7 @@ class Connection
}
}
public function add(string $body, array $headers)
public function add(string $body, array $headers): void
{
$e = null;
try {

View File

@ -11,14 +11,14 @@
namespace Symfony\Component\Messenger\Transport\RedisExt;
use Symfony\Component\Messenger\Stamp\StampInterface;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
/**
* @author Alexander Schranz <alexander@sulu.io>
*
* @experimental in 4.3
*/
class RedisReceivedStamp implements StampInterface
class RedisReceivedStamp implements NonSendableStampInterface
{
private $id;

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Messenger\Transport\Serialization;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
/**
* @author Ryan Weaver<ryan@symfonycasts.com>
@ -40,6 +41,8 @@ class PhpSerializer implements SerializerInterface
*/
public function encode(Envelope $envelope): array
{
$envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class);
$body = addslashes(serialize($envelope));
return [

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Transport\Serialization;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\LogicException;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
use Symfony\Component\Messenger\Stamp\SerializerStamp;
use Symfony\Component\Messenger\Stamp\StampInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
@ -47,7 +48,7 @@ class Serializer implements SerializerInterface
public static function create(): self
{
if (!class_exists(SymfonySerializer::class)) {
throw new LogicException(sprintf('The default Messenger Serializer requires Symfony\'s Serializer component. Try running "composer require symfony/serializer".'));
throw new LogicException(sprintf('The "%s" class requires Symfony\'s Serializer component. Try running "composer require symfony/serializer" or use "%s" instead.', __CLASS__, PhpSerializer::class));
}
$encoders = [new XmlEncoder(), new JsonEncoder()];
@ -98,6 +99,8 @@ class Serializer implements SerializerInterface
$context = $serializerStamp->getContext() + $context;
}
$envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class);
$headers = ['type' => \get_class($envelope->getMessage())] + $this->encodeStamps($envelope);
return [

View File

@ -39,6 +39,9 @@ interface SerializerInterface
* Encodes an envelope content (message & stamps) to a common format understandable by transports.
* The encoded array should only contain scalars and arrays.
*
* Stamps that implement NonSendableStampInterface should
* not be encoded.
*
* The most common keys of the encoded array are:
* - `body` (string) - the message body
* - `headers` (string<string>) - a key/value pair of headers

View File

@ -1157,6 +1157,7 @@ final class MimeTypes implements MimeTypesInterface
'audio/x-flac' => ['flac'],
'audio/x-flac+ogg' => ['oga', 'ogg'],
'audio/x-gsm' => ['gsm'],
'audio/x-hx-aac-adts' => ['aac', 'adts', 'ass'],
'audio/x-imelody' => ['imy', 'ime'],
'audio/x-iriver-pla' => ['pla'],
'audio/x-it' => ['it'],
@ -1631,7 +1632,7 @@ final class MimeTypes implements MimeTypesInterface
'a78' => ['application/x-atari-7800-rom'],
'aa' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'],
'aab' => ['application/x-authorware-bin'],
'aac' => ['audio/aac', 'audio/x-aac'],
'aac' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'],
'aam' => ['application/x-authorware-map'],
'aas' => ['application/x-authorware-seg'],
'aax' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'],
@ -1648,7 +1649,7 @@ final class MimeTypes implements MimeTypesInterface
'adf' => ['application/x-amiga-disk-format'],
'adp' => ['audio/adpcm'],
'ads' => ['text/x-adasrc'],
'adts' => ['audio/aac', 'audio/x-aac'],
'adts' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'],
'aep' => ['application/vnd.audiograph'],
'afm' => ['application/x-font-afm', 'application/x-font-type1'],
'afp' => ['application/vnd.ibm.modcap'],
@ -1687,7 +1688,7 @@ final class MimeTypes implements MimeTypesInterface
'asm' => ['text/x-asm'],
'aso' => ['application/vnd.accpac.simply.aso'],
'asp' => ['application/x-asp'],
'ass' => ['audio/aac', 'audio/x-aac', 'text/x-ssa'],
'ass' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'],
'asx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-asf', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'],
'atc' => ['application/vnd.acucorp'],
'atom' => ['application/atom+xml'],

View File

@ -199,7 +199,15 @@ abstract class AbstractToken implements TokenInterface
*/
public function __unserialize(array $data): void
{
[$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames] = $data;
[$this->user, $this->authenticated, $this->roles, $this->attributes] = $data;
// migration path to 4.3+
if (null === $this->roleNames = $data[4] ?? null) {
$this->roleNames = [];
foreach ($this->roles as $role) {
$this->roleNames[] = (string) $role;
}
}
}
/**

View File

@ -68,10 +68,10 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
{
if ($this->translator instanceof TranslatorInterface) {
$trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
} else {
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
}
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
$this->collectMessage($locale, $domain, $id, $trans, ['%count%' => $number] + $parameters);
return $trans;