From d261bb5dd10e786aaf185bd44e9cc37469792828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Thu, 9 May 2019 15:04:55 +0200 Subject: [PATCH 01/23] Fix finding parent definition --- .../DependencyInjection/AddValidatorInitializersPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php b/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php index dcc02ca694..d7bea0fb73 100644 --- a/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php +++ b/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php @@ -62,7 +62,7 @@ class AddValidatorInitializersPass implements CompilerPassInterface } while (!($class = $translator->getClass()) && $translator instanceof ChildDefinition) { - $translator = $translator->getParent(); + $translator = $container->findDefinition($translator->getParent()); } if (!is_subclass_of($class, LegacyTranslatorInterface::class)) { From d88446be072ea3466eda4673f1611364cac5528a Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 9 May 2019 11:10:11 -0400 Subject: [PATCH 02/23] Making cache rebuild correctly with MessageSubscriberInterface return values --- .../Resource/ReflectionClassResource.php | 8 +++++ .../Resource/ReflectionClassResourceTest.php | 33 +++++++++++++++++++ src/Symfony/Component/Config/composer.json | 1 + 3 files changed, 42 insertions(+) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index a7e73becf5..3890dd29ed 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Config\Resource; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface as LegacyServiceSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; /** @@ -164,6 +165,13 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali yield print_r($class->name::getSubscribedEvents(), true); } + if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) { + yield MessageSubscriberInterface::class; + foreach ($class->name::getHandledMessages() as $key => $value) { + yield $key.print_r($value, true); + } + } + if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) { yield LegacyServiceSubscriberInterface::class; yield print_r([$class->name, 'getSubscribedServices'](), true); diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php index abc461cd7c..e22933245d 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\Resource\ReflectionClassResource; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; class ReflectionClassResourceTest extends TestCase { @@ -147,6 +148,24 @@ EOPHP; $this->assertTrue($res->isFresh(0)); } + public function testMessageSubscriber() + { + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + + TestMessageSubscriberConfigHolder::$handledMessages = ['SomeMessageClass' => []]; + $this->assertFalse($res->isFresh(0)); + + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + + TestMessageSubscriberConfigHolder::$handledMessages = ['OtherMessageClass' => []]; + $this->assertFalse($res->isFresh(0)); + + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + } + public function testServiceSubscriber() { $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class)); @@ -174,6 +193,20 @@ class TestEventSubscriber implements EventSubscriberInterface } } +class TestMessageSubscriber implements MessageSubscriberInterface +{ + public static function getHandledMessages(): iterable + { + foreach (TestMessageSubscriberConfigHolder::$handledMessages as $key => $subscribedMessage) { + yield $key => $subscribedMessage; + } + } +} +class TestMessageSubscriberConfigHolder +{ + public static $handledMessages = []; +} + class TestServiceSubscriber implements ServiceSubscriberInterface { public static $subscribedServices = []; diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index 35fbffdb69..00a88e81b5 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -24,6 +24,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/event-dispatcher": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", + "symfony/messenger": "~4.1", "symfony/yaml": "~3.4|~4.0" }, "conflict": { From 8bac3d6fa31908cbdd02b41e32f14467b228cd96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20G=C3=B3mez=20Vilches?= Date: Fri, 10 May 2019 21:58:31 +0200 Subject: [PATCH 03/23] Allow set 'None' on samesite cookie flag Allow set samesite cookie flag to 'None' value --- src/Symfony/Component/HttpFoundation/Cookie.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php index e61619aa6d..83a97087f1 100644 --- a/src/Symfony/Component/HttpFoundation/Cookie.php +++ b/src/Symfony/Component/HttpFoundation/Cookie.php @@ -28,6 +28,7 @@ class Cookie private $raw; private $sameSite; + const SAMESITE_NONE = 'none'; const SAMESITE_LAX = 'lax'; const SAMESITE_STRICT = 'strict'; @@ -128,7 +129,7 @@ class Cookie $sameSite = strtolower($sameSite); } - if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, null], true)) { + if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, self::SAMESITE_NONE, null], true)) { throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); } From c8c3c56cc8e579801fc1acb36fba019a7afe5774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Thu, 9 May 2019 08:43:47 +0200 Subject: [PATCH 04/23] [Serializer] Fix denormalization of object with variadic constructor typed argument --- .../Normalizer/AbstractNormalizer.php | 8 +++++- .../VariadicConstructorTypedArgsDummy.php | 27 +++++++++++++++++++ .../Normalizer/AbstractNormalizerTest.php | 21 +++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index c5bd3ffd97..00bd8a2a52 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -354,7 +354,13 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name)); } - $params = array_merge($params, $data[$paramName]); + $variadicParameters = []; + foreach ($data[$paramName] as $parameterData) { + $variadicParameters[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); + } + + $params = array_merge($params, $variadicParameters); + unset($data[$key]); } } elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) { $parameterData = $data[$key]; diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php new file mode 100644 index 0000000000..9c6fd980a1 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class VariadicConstructorTypedArgsDummy +{ + private $foo; + + public function __construct(Dummy ...$foo) + { + $this->foo = $foo; + } + + public function getFoo() + { + return $this->foo; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index 890cb27019..cce383075a 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -8,11 +8,15 @@ use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy; +use Symfony\Component\Serializer\Tests\Fixtures\Dummy; use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy; use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer; +use Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorTypedArgsDummy; /** * Provides a dummy Normalizer which extends the AbstractNormalizer. @@ -128,4 +132,21 @@ class AbstractNormalizerTest extends TestCase $this->assertNull($dummy->getFoo()); } + + /** + * @requires PHP 5.6 + */ + public function testObjectWithVariadicConstructorTypedArguments() + { + $normalizer = new PropertyNormalizer(); + $normalizer->setSerializer(new Serializer([$normalizer])); + $data = ['foo' => [['foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz', 'qux' => 'Qux'], ['foo' => 'FOO', 'bar' => 'BAR', 'baz' => 'BAZ', 'qux' => 'QUX']]]; + $dummy = $normalizer->denormalize($data, VariadicConstructorTypedArgsDummy::class); + + $this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy); + $this->assertCount(2, $dummy->getFoo()); + foreach ($dummy->getFoo() as $foo) { + $this->assertInstanceOf(Dummy::class, $foo); + } + } } From 4443c2018cebe7cd6e1b8d9bd342c36d5c55fb07 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 11 May 2019 20:03:05 +0200 Subject: [PATCH 05/23] [Cache] fix saving unrelated keys in recursive callback calls --- .../Cache/Tests/Adapter/AdapterTestCase.php | 20 +++++++++++++++++++ .../Tests/Adapter/PhpArrayAdapterTest.php | 1 + .../Component/Cache/Traits/ContractsTrait.php | 12 ++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 0eceb6e572..498c00ca64 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -59,6 +59,26 @@ abstract class AdapterTestCase extends CachePoolTest $this->assertFalse($isHit); } + public function testRecursiveGet() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $v = $cache->get('k1', function () use (&$counter, $cache) { + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + + return $v; + }); + + $this->assertSame(1, $counter); + $this->assertSame(1, $v); + $this->assertSame(1, $cache->get('k2', function () { return 2; })); + } + public function testGetMetadata() { if (isset($this->skippedTests[__FUNCTION__])) { diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index cee80ac196..3a5904b107 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -23,6 +23,7 @@ class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = [ 'testGet' => 'PhpArrayAdapter is read-only.', + 'testRecursiveGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', 'testClear' => 'PhpArrayAdapter is read-only.', diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php index bd7be08dd5..6d602dfece 100644 --- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php +++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php @@ -31,6 +31,7 @@ trait ContractsTrait } private $callbackWrapper = [LockRegistry::class, 'compute']; + private $computing = []; /** * Wraps the callback passed to ->get() in a callable. @@ -68,26 +69,27 @@ trait ContractsTrait CacheItem::class ); - return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) { + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { // don't wrap nor save recursive calls - if (null === $callbackWrapper = $this->callbackWrapper) { + if (isset($this->computing[$key])) { $value = $callback($item, $save); $save = false; return $value; } - $this->callbackWrapper = null; + + $this->computing[$key] = $key; $startTime = microtime(true); try { - $value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); }); $setMetadata($item, $startTime, $metadata); return $value; } finally { - $this->callbackWrapper = $callbackWrapper; + unset($this->computing[$key]); } }, $beta, $metadata); } From b1d3736c409ba5f6c85f2a12d388dad3571ed474 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 11 May 2019 14:25:26 +0300 Subject: [PATCH 06/23] [PropertyAccess] Add missing property to PropertyAccessor --- src/Symfony/Component/PropertyAccess/PropertyAccessor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 6bf6e21096..2eb3d17ea9 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -62,6 +62,7 @@ class PropertyAccessor implements PropertyAccessorInterface */ private $cacheItemPool; + private $propertyPathCache = []; private $readPropertyCache = []; private $writePropertyCache = []; private static $resultProto = [self::VALUE => null]; @@ -795,7 +796,7 @@ class PropertyAccessor implements PropertyAccessorInterface * * @return AdapterInterface * - * @throws RuntimeException When the Cache Component isn't available + * @throws \LogicException When the Cache Component isn't available */ public static function createCache($namespace, $defaultLifetime, $version, LoggerInterface $logger = null) { From 710f8a63676f514f1c15df0b6e0f3021baf08903 Mon Sep 17 00:00:00 2001 From: gauss Date: Tue, 14 May 2019 17:13:30 +0300 Subject: [PATCH 07/23] [Validator] Add the missing translations for the Danish ("da") locale --- .../Resources/translations/validators.da.xlf | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf index f52f4e0a30..346e7cf574 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf @@ -14,6 +14,122 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF-token er ugyldig. + + This value is not a valid currency. + Denne værdi er ikke en gyldig valuta. + + + This value should be equal to {{ compared_value }}. + Denne værdi skal være lig med {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Denne værdi skal være større end {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Denne værdi skal være større end eller lig med {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Denne værdi skal være identisk med {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Denne værdi skal være mindre end {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Denne værdi skal være mindre end eller lig med {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Denne værdi bør ikke være lig med {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Denne værdi bør ikke være identisk med {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Billedforholdet er for stort ({{ratio}}). Tilladt maksimumsforhold er {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Billedforholdet er for lille ({{ ratio }}). Minimumsforventet forventet er {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Billedet er firkantet ({{ width }} x {{ height }} px). Firkantede billeder er ikke tilladt. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Billedet er landskabsorienteret ({{width}} x {{height}} px). Landskabsorienterede billeder er ikke tilladt + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Billedet er portrætorienteret ({{ width }}x{{ height }}px). Portrætorienterede billeder er ikke tilladt. + + + An empty file is not allowed. + En tom fil er ikke tilladt. + + + The host could not be resolved. + Værten kunne ikke løses. + + + This value does not match the expected {{ charset }} charset. + Denne værdi stemmer ikke overens med den forventede {{ charset }} charset. + + + This is not a valid Business Identifier Code (BIC). + Dette er ikke en gyldig Business Identifier Code (BIC).a + + + This is not a valid UUID. + Dette er ikke en gyldig UUID. + + + This value should be a multiple of {{ compared_value }}. + Denne værdi skal være et flertal af {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Denne Business Identifier Code (BIC) er ikke forbundet med IBAN {{ iban }}. + + + This value should be valid JSON. + Denne værdi skal være gyldig JSON. + + + This collection should contain only unique elements. + Denne samling bør kun indeholde unikke elementer. + + + This value should be positive. + Denne værdi skal være positiv. + + + This value should be either positive or zero. + Denne værdi skal være enten positiv eller nul. + + + This value should be negative. + Denne værdi skal være negativ. + + + This value should be either negative or zero. + Denne værdi skal være enten negativ eller nul. + + + This value is not a valid timezone. + Denne værdi er ikke en gyldig tidszone. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Denne adgangskode er blevet lækket i et databrud, det må ikke bruges. Brug venligst en anden adgangskode. + From 70fdafd79f9cc5249ad24f0eb27e4b35bafd3976 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Wed, 15 May 2019 07:52:16 +0200 Subject: [PATCH 08/23] [WebProfilerBundle][Form] The form data collector return serialized object when profiler bundle attends object --- src/Symfony/Bundle/WebProfilerBundle/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index bc15238fbc..cbd0f38dd1 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -32,7 +32,8 @@ "conflict": { "symfony/dependency-injection": "<3.4", "symfony/messenger": "<4.2", - "symfony/var-dumper": "<3.4" + "symfony/var-dumper": "<3.4", + "symfony/form": "<4.3" }, "autoload": { "psr-4": { "Symfony\\Bundle\\WebProfilerBundle\\": "" }, From 42d62721fd84c1b9004ea12c36b89f714c23d601 Mon Sep 17 00:00:00 2001 From: Konstantin Myakshin Date: Wed, 1 May 2019 00:27:11 +0300 Subject: [PATCH 09/23] Respect parent class contract in ContainerAwareDoctrineEventManager --- .../Doctrine/ContainerAwareEventManager.php | 89 ++++++++++--------- .../Tests/ContainerAwareEventManagerTest.php | 70 ++++++++++++--- 2 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index 66b99ecf62..4496d3ac9a 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -37,51 +37,49 @@ class ContainerAwareEventManager extends EventManager } /** - * Dispatches an event to all registered listeners. - * - * @param string $eventName The name of the event to dispatch. The name of the event is - * the name of the method that is invoked on listeners. - * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. - * If not supplied, the single empty EventArgs instance is used. - * - * @return bool + * {@inheritdoc} */ public function dispatchEvent($eventName, EventArgs $eventArgs = null) { - if (isset($this->listeners[$eventName])) { - $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; + if (!isset($this->listeners[$eventName])) { + return; + } - $initialized = isset($this->initialized[$eventName]); + $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; - foreach ($this->listeners[$eventName] as $hash => $listener) { - if (!$initialized && \is_string($listener)) { - $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener); - } + if (!isset($this->initialized[$eventName])) { + $this->initializeListeners($eventName); + } - $listener->$eventName($eventArgs); - } - $this->initialized[$eventName] = true; + foreach ($this->listeners[$eventName] as $hash => $listener) { + $listener->$eventName($eventArgs); } } /** - * Gets the listeners of a specific event or all listeners. - * - * @param string $event The name of the event - * - * @return array The event listeners for the specified event, or all event listeners + * {@inheritdoc} */ public function getListeners($event = null) { - return $event ? $this->listeners[$event] : $this->listeners; + if (null !== $event) { + if (!isset($this->initialized[$event])) { + $this->initializeListeners($event); + } + + return $this->listeners[$event]; + } + + foreach ($this->listeners as $event => $listeners) { + if (!isset($this->initialized[$event])) { + $this->initializeListeners($event); + } + } + + return $this->listeners; } /** - * Checks whether an event has any registered listeners. - * - * @param string $event - * - * @return bool TRUE if the specified event has any listeners, FALSE otherwise + * {@inheritdoc} */ public function hasListeners($event) { @@ -89,20 +87,11 @@ class ContainerAwareEventManager extends EventManager } /** - * Adds an event listener that listens on the specified events. - * - * @param string|array $events The event(s) to listen on - * @param object|string $listener The listener object - * - * @throws \RuntimeException + * {@inheritdoc} */ public function addEventListener($events, $listener) { if (\is_string($listener)) { - if ($this->initialized) { - throw new \RuntimeException('Adding lazy-loading listeners after construction is not supported.'); - } - $hash = '_service_'.$listener; } else { // Picks the hash code related to that listener @@ -113,14 +102,15 @@ class ContainerAwareEventManager extends EventManager // Overrides listener if a previous one was associated already // Prevents duplicate listeners on same event (same instance only) $this->listeners[$event][$hash] = $listener; + + if (\is_string($listener)) { + unset($this->initialized[$event]); + } } } /** - * Removes an event listener from the specified events. - * - * @param string|array $events - * @param object|string $listener + * {@inheritdoc} */ public function removeEventListener($events, $listener) { @@ -138,4 +128,17 @@ class ContainerAwareEventManager extends EventManager } } } + + /** + * @param string $eventName + */ + private function initializeListeners($eventName) + { + foreach ($this->listeners[$eventName] as $hash => $listener) { + if (\is_string($listener)) { + $this->listeners[$eventName][$hash] = $this->container->get($listener); + } + } + $this->initialized[$eventName] = true; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index 2e97edb1d2..b3fb8bc3ac 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -28,8 +28,8 @@ class ContainerAwareEventManagerTest extends TestCase public function testDispatchEvent() { - $this->container->set('foobar', $listener1 = new MyListener()); - $this->evm->addEventListener('foo', 'foobar'); + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); $this->evm->addEventListener('foo', $listener2 = new MyListener()); $this->evm->dispatchEvent('foo'); @@ -38,19 +38,69 @@ class ContainerAwareEventManagerTest extends TestCase $this->assertTrue($listener2->called); } + public function testAddEventListenerAfterDispatchEvent() + { + $this->container->set('lazy1', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy1'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->evm->dispatchEvent('foo'); + + $this->container->set('lazy2', $listener3 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy2'); + $this->evm->addEventListener('foo', $listener4 = new MyListener()); + + $this->evm->dispatchEvent('foo'); + + $this->assertTrue($listener1->called); + $this->assertTrue($listener2->called); + $this->assertTrue($listener3->called); + $this->assertTrue($listener4->called); + } + + public function testGetListenersForEvent() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners('foo'))); + } + + public function testGetListeners() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners()['foo'])); + } + public function testRemoveEventListener() { - $this->evm->addEventListener('foo', 'bar'); - $this->evm->addEventListener('foo', $listener = new MyListener()); + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); - $listeners = ['foo' => ['_service_bar' => 'bar', spl_object_hash($listener) => $listener]]; - $this->assertSame($listeners, $this->evm->getListeners()); - $this->assertSame($listeners['foo'], $this->evm->getListeners('foo')); + $this->evm->removeEventListener('foo', $listener2); + $this->assertSame([$listener1], array_values($this->evm->getListeners('foo'))); - $this->evm->removeEventListener('foo', $listener); - $this->assertSame(['_service_bar' => 'bar'], $this->evm->getListeners('foo')); + $this->evm->removeEventListener('foo', 'lazy'); + $this->assertSame([], $this->evm->getListeners('foo')); + } - $this->evm->removeEventListener('foo', 'bar'); + public function testRemoveEventListenerAfterDispatchEvent() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->evm->dispatchEvent('foo'); + + $this->evm->removeEventListener('foo', $listener2); + $this->assertSame([$listener1], array_values($this->evm->getListeners('foo'))); + + $this->evm->removeEventListener('foo', 'lazy'); $this->assertSame([], $this->evm->getListeners('foo')); } } From 6b76c365ead7f28743c2262abb2076fe1f001759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 16 May 2019 11:52:39 +0200 Subject: [PATCH 10/23] Use the current working dir as default first arg in 'link' binary --- link | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/link b/link index 6a2ec15e22..95a3142d2a 100755 --- a/link +++ b/link @@ -23,14 +23,12 @@ use Symfony\Component\Filesystem\Filesystem; * @author Kévin Dunglas */ -if (2 !== $argc) { - echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; - echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; - exit(1); -} +$pathToProject = $argv[1] ?? getcwd(); -if (!is_dir("$argv[1]/vendor/symfony")) { - echo "The directory \"$argv[1]\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; +if (!is_dir("$pathToProject/vendor/symfony")) { + echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; + echo "Usage: $argv[0] /path/to/the/project".PHP_EOL.PHP_EOL; + echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; exit(1); } @@ -48,7 +46,7 @@ foreach ($directories as $dir) { } } -foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { +foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { $package = 'symfony/'.basename($dir); if (is_link($dir)) { echo "\"$package\" is already a symlink, skipping.".PHP_EOL; @@ -66,6 +64,6 @@ foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; } -foreach (glob("$argv[1]/var/cache/*") as $cacheDir) { +foreach (glob("$pathToProject/var/cache/*") as $cacheDir) { $filesystem->remove($cacheDir); } From 62894ed8b95834bd8c1e3d439fa45cb177b612cd Mon Sep 17 00:00:00 2001 From: Pablo Lozano Date: Thu, 16 May 2019 15:56:20 +0200 Subject: [PATCH 11/23] [PropertyInfo] Add missing documentation link in Readme --- src/Symfony/Component/PropertyInfo/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/PropertyInfo/README.md b/src/Symfony/Component/PropertyInfo/README.md index 5ac21f384e..1cf30318de 100644 --- a/src/Symfony/Component/PropertyInfo/README.md +++ b/src/Symfony/Component/PropertyInfo/README.md @@ -7,6 +7,7 @@ of popular sources. Resources --------- + * [Documentation](https://symfony.com/doc/current/components/property_info.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) From d836c63b919aad261be315a75aa09b2b22e3c8f5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 May 2019 13:55:16 +0200 Subject: [PATCH 12/23] prevent deprecation when filesize matches error code --- src/Symfony/Component/HttpFoundation/FileBag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/FileBag.php b/src/Symfony/Component/HttpFoundation/FileBag.php index 14fbc7aa9d..efd83ffeb8 100644 --- a/src/Symfony/Component/HttpFoundation/FileBag.php +++ b/src/Symfony/Component/HttpFoundation/FileBag.php @@ -84,7 +84,7 @@ class FileBag extends ParameterBag if (UPLOAD_ERR_NO_FILE == $file['error']) { $file = null; } else { - $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); + $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error'], false); } } else { $file = array_map([$this, 'convertFileInformation'], $file); From 20c587fc23a0fa62c6b68928c99435ae1b875935 Mon Sep 17 00:00:00 2001 From: Wojciech Skorodecki Date: Fri, 17 May 2019 15:28:19 +0200 Subject: [PATCH 13/23] [EventDispatcher] Removed "callable" type hint from WrappedListener constructor --- src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 34316b54c3..3991c0165f 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -38,7 +38,7 @@ class WrappedListener private $priority; private static $hasClassStub; - public function __construct(callable $listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) + public function __construct($listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) { $this->listener = $listener; $this->optimizedListener = $listener instanceof \Closure ? $listener : \Closure::fromCallable($listener); From afb6e1ec9ebe5e60cdcb660667ada2bc83fe6bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Sat, 18 May 2019 15:32:47 +0200 Subject: [PATCH 14/23] [Debug] Wrap call to require_once in a try/catch If the included file contains an error, it hides the real error. This makes debugging harder. How to reproduce: ``` composer create-project symfony/skeleton symfony-3.4 3.4 cd symfony-3.4 composer req monolog ``` Add to `monolog.yaml`: ```yaml elasticsearch: type: "elasticsearch" elasticsearch: host: 'elasticsearch' port: '9200' index: 'ep_php_logs_dev' level: 'debug' tags: 'monolog.logger' channels: ['!event'] ``` This will fail because the the \Elastica\Client class does not exist. But this error will be hidden by the `ClassNotFoundFatalErrorHandler` because it will try to load the `Symfony\Component\Kernel\Client` and this class extends `Symfony\Component\BrowserKit\Client`. The last one is a soft dependency... --- Before ``` Fatal error: Uncaught Error: Class 'Symfony\Component\BrowserKit\Client' not found in /tmp/symfony-3.4/vendor/symfony/http-kernel/Client.php:31 ``` After: ``` Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "Client" from namespace "Elastica". Did you forget a "use" statement for another namespace? in /tmp/symfony-es/var/cache/dev/ContainerWXN4mS9/srcApp_KernelDevDebugContainer.php:303 ``` --- .../FatalErrorHandler/ClassNotFoundFatalErrorHandler.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index 1ac18ac8f5..45dcc00d5c 100644 --- a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -185,7 +185,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface } } - require_once $file; + try { + require_once $file; + } catch (\Throwable $e) { + return null; + } foreach ($candidates as $candidate) { if ($this->classExists($candidate)) { From c866efa61509e741d8e6216c429a572f079355ff Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 18 May 2019 18:33:51 +0200 Subject: [PATCH 15/23] fixed a phpdoc --- .../HttpFoundation/Session/Flash/FlashBagInterface.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php index 2bd1d62bdb..99e8074214 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php @@ -21,7 +21,7 @@ use Symfony\Component\HttpFoundation\Session\SessionBagInterface; interface FlashBagInterface extends SessionBagInterface { /** - * Adds a flash message for type. + * Adds a flash message for the given type. * * @param string $type * @param mixed $message @@ -29,12 +29,12 @@ interface FlashBagInterface extends SessionBagInterface public function add($type, $message); /** - * Registers a message for a given type. + * Registers one or more messages for a given type. * * @param string $type - * @param string|array $message + * @param string|array $messages */ - public function set($type, $message); + public function set($type, $messages); /** * Gets flash messages for a given type. From 7ab52d3c36096a2e8b01b3e5df63305c0e91ab9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= Date: Wed, 8 May 2019 14:03:42 +0200 Subject: [PATCH 16/23] [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name --- .../Routing/Loader/AnnotationClassLoader.php | 3 ++- .../AnnotatedClasses/EncodingClass.php | 10 +++++++++ .../Loader/AnnotationClassLoaderTest.php | 21 +++++++++++++++++++ .../Loader/AnnotationDirectoryLoaderTest.php | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index 6a439e710a..6b8a50efb7 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -199,7 +199,8 @@ abstract class AnnotationClassLoader implements LoaderInterface */ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method) { - $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name); + $name = str_replace('\\', '_', $class->name).'_'.$method->name; + $name = \function_exists('mb_strtolower') && preg_match('//u', $name) ? mb_strtolower($name, 'UTF-8') : strtolower($name); if ($this->defaultRouteIndex > 0) { $name .= '_'.$this->defaultRouteIndex; } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php new file mode 100644 index 0000000000..dac72e3ddc --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php @@ -0,0 +1,10 @@ +assertEquals(array_merge($classRouteData['methods'], $methodRouteData['methods']), $route->getMethods(), '->load merges class and method route methods'); } + /** + * @requires function mb_strtolower + */ + public function testDefaultRouteName() + { + $methodRouteData = [ + 'name' => null, + ]; + + $this->reader + ->expects($this->once()) + ->method('getMethodAnnotations') + ->will($this->returnValue([$this->getAnnotatedRoute($methodRouteData)])) + ; + + $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass'); + $defaultName = array_keys($routeCollection->all())[0]; + + $this->assertSame($defaultName, 'symfony_component_routing_tests_fixtures_annotatedclasses_encodingclass_routeàction'); + } + private function getAnnotatedRoute($data) { return new Route($data); diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php index ac25493481..9465ef05df 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php @@ -29,7 +29,7 @@ class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest public function testLoad() { - $this->reader->expects($this->exactly(3))->method('getClassAnnotation'); + $this->reader->expects($this->exactly(4))->method('getClassAnnotation'); $this->reader ->expects($this->any()) @@ -52,6 +52,7 @@ class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass', + 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass', ]); $this->reader From a2191678b71de60764e3c0e45a951fdf40c7d8b7 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Sun, 19 May 2019 00:39:11 +0200 Subject: [PATCH 17/23] [Workflow] use method marking store --- src/Symfony/Component/Workflow/StateMachine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Workflow/StateMachine.php b/src/Symfony/Component/Workflow/StateMachine.php index c9f88a022b..05f4c291da 100644 --- a/src/Symfony/Component/Workflow/StateMachine.php +++ b/src/Symfony/Component/Workflow/StateMachine.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Workflow; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; -use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -22,6 +22,6 @@ class StateMachine extends Workflow { public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, string $name = 'unnamed') { - parent::__construct($definition, $markingStore ?: new SingleStateMarkingStore(), $dispatcher, $name); + parent::__construct($definition, $markingStore ?: new MethodMarkingStore(true, 'marking'), $dispatcher, $name); } } From fd8d6b8187a1a70c64db5d23887273ae112db9d3 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 19 May 2019 16:33:13 +0200 Subject: [PATCH 18/23] [Messenger] Fix undefined index on read timeout --- .../Transport/RedisExt/ConnectionTest.php | 18 +++++++++++++++++- .../Transport/RedisExt/Connection.php | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php index fae72fa781..c2654d326d 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php @@ -115,7 +115,8 @@ class ConnectionTest extends TestCase public function testGetAfterReject() { - $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget'); + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', [], $redis); try { $connection->setup(); } catch (TransportException $e) { @@ -129,5 +130,20 @@ class ConnectionTest extends TestCase $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget'); $this->assertNotNull($connection->get()); + + $redis->del('messenger-rejectthenget'); + } + + public function testBlockingTimeout() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/messenger-blockingtimeout', ['blocking_timeout' => 1], $redis); + try { + $connection->setup(); + } catch (TransportException $e) { + } + + $this->assertNull($connection->get()); + $redis->del('messenger-blockingtimeout'); } } diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 66dc9fe9d6..566e3d6c62 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -102,7 +102,7 @@ class Connection return $this->get(); } - foreach ($messages[$this->stream] as $key => $message) { + foreach ($messages[$this->stream] ?? [] as $key => $message) { $redisEnvelope = \json_decode($message['message'], true); return [ From 964acd9110ac4f44f6f8b28966f858815e48f76e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 May 2019 10:47:09 -0300 Subject: [PATCH 19/23] [HttpClient] add missing argument check --- src/Symfony/Component/HttpClient/ScopingHttpClient.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/HttpClient/ScopingHttpClient.php b/src/Symfony/Component/HttpClient/ScopingHttpClient.php index 5b1da579bc..cc5872b3e5 100644 --- a/src/Symfony/Component/HttpClient/ScopingHttpClient.php +++ b/src/Symfony/Component/HttpClient/ScopingHttpClient.php @@ -36,6 +36,10 @@ class ScopingHttpClient implements HttpClientInterface $this->client = $client; $this->defaultOptionsByRegexp = $defaultOptionsByRegexp; $this->defaultRegexp = $defaultRegexp; + + if (null !== $defaultRegexp && !isset($defaultOptionsByRegexp[$defaultRegexp])) { + throw new InvalidArgumentException(sprintf('No options are mapped to the provided "%s" default regexp.', $defaultRegexp)); + } } public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], $regexp = null): self From 5175f6fffc3fb07f7544a0d3d2856b7501e24343 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Mon, 20 May 2019 11:28:54 +0200 Subject: [PATCH 20/23] adding experimental note --- src/Symfony/Component/Mailer/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Component/Mailer/README.md b/src/Symfony/Component/Mailer/README.md index 0f70cc30d7..d6fc297909 100644 --- a/src/Symfony/Component/Mailer/README.md +++ b/src/Symfony/Component/Mailer/README.md @@ -3,6 +3,11 @@ Mailer Component The Mailer component helps sending emails. +**This Component is experimental**. +[Experimental features](https://symfony.com/doc/current/contributing/code/experimental.html) +are not covered by Symfony's +[Backward Compatibility Promise](https://symfony.com/doc/current/contributing/code/bc.html). + Resources --------- From e3739b1289fe2d10eacc92462e198271e4338216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Mon, 20 May 2019 12:27:33 +0200 Subject: [PATCH 21/23] [Bridge\ProxyManager] isProxyCandidate() does not take into account interfaces When using factories it's common best practice to use interface as class name, especially in cases where you know impl can differ. Before this fix ProxyManager did not allow these to be lazy. In our case this has lead several to hard to debug issues on classes we need to mark as lazyi and often a need to add lazy on decorators if there are any or other workarounds. As we have had this issue, and still have on both 2.8 and 3.4 this is opened against 2.8. --- .../Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php | 2 +- .../ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index 4ee40def66..7c12b7015e 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -47,7 +47,7 @@ class ProxyDumper implements DumperInterface */ public function isProxyCandidate(Definition $definition) { - return $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class); + return $definition->isLazy() && ($class = $definition->getClass()) && (class_exists($class) || interface_exists($class)); } /** diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php index 2f7ee38cce..f0822d4616 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface; /** * Tests for {@see \Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper}. @@ -137,6 +138,7 @@ class ProxyDumperTest extends TestCase $definitions = [ [new Definition(__CLASS__), true], [new Definition('stdClass'), true], + [new Definition(DumperInterface::class), true], [new Definition(uniqid('foo', true)), false], [new Definition(), false], ]; From c8636523d362ab1a5310a4a8d95f03282cbb954c Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Sat, 18 May 2019 23:50:26 +0200 Subject: [PATCH 22/23] [Workflow] Update MethodMarkingStore --- .../Component/Workflow/MarkingStore/MethodMarkingStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php index 3e6294b0fa..a2341aadbd 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php @@ -20,7 +20,7 @@ use Symfony\Component\Workflow\Marking; * This store deals with a "single state" or "multiple state" Marking. * * "single state" Marking means a subject can be in one and only one state at - * the same time. Use it with state machine or specific workflow. + * the same time. Use it with state machine. * * "multiple state" Marking means a subject can be in many states at the same * time. Use it with workflow. From d08f195502190683b4b440ef579503ebc3e3edc1 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Sat, 18 May 2019 09:12:43 +0200 Subject: [PATCH 23/23] minor: add some test in the ldap component --- .../Adapter/ExtLdap/EntryManagerTest.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php new file mode 100644 index 0000000000..0617762ed6 --- /dev/null +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Ldap\Tests\Adapter\ExtLdap; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Ldap\Adapter\ExtLdap\Connection; +use Symfony\Component\Ldap\Adapter\ExtLdap\EntryManager; +use Symfony\Component\Ldap\Entry; + +class EntryManagerTest extends TestCase +{ + /** + * @expectedException \Symfony\Component\Ldap\Exception\NotBoundException + * @expectedExceptionMessage Query execution is not possible without binding the connection first. + */ + public function testGetResources() + { + $connection = $this->getMockBuilder(Connection::class)->getMock(); + $connection + ->expects($this->once()) + ->method('isBound')->willReturn(false); + + $entry = new Entry('$$$$$$'); + $entryManager = new EntryManager($connection); + $entryManager->update($entry); + } +}