diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index 0b14604d5a..a7b3b11272 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -99,7 +99,19 @@ class DeprecationErrorHandler
return \call_user_func(self::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context);
}
- $deprecations[] = [error_reporting(), $msg, $file];
+ $trace = debug_backtrace();
+ $filesStack = [];
+ foreach ($trace as $line) {
+ if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
+ continue;
+ }
+
+ if (isset($line['file'])) {
+ $filesStack[] = $line['file'];
+ }
+ }
+
+ $deprecations[] = [error_reporting(), $msg, $file, $filesStack];
return null;
});
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
index 6263267fef..55909ee6cf 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
@@ -44,6 +44,8 @@ class Deprecation
*/
private static $internalPaths = [];
+ private $originalFilesStack;
+
/**
* @param string $message
* @param string $file
@@ -64,6 +66,7 @@ class Deprecation
$this->message = $parsedMsg['deprecation'];
$this->originClass = $parsedMsg['class'];
$this->originMethod = $parsedMsg['method'];
+ $this->originalFilesStack = $parsedMsg['files_stack'];
// If the deprecation has been triggered via
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
// then we need to use the serialized information to determine
@@ -162,6 +165,24 @@ class Deprecation
return false !== strpos($this->triggeringFile, \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR.'phpunit'.\DIRECTORY_SEPARATOR);
}
+ private function getOriginalFilesStack(): array
+ {
+ if (null === $this->originalFilesStack) {
+ $this->originalFilesStack = [];
+ foreach ($this->trace as $line) {
+ if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
+ continue;
+ }
+ if (!isset($line['file'])) {
+ continue;
+ }
+ $this->originalFilesStack[] = $line['file'];
+ }
+ }
+
+ return $this->originalFilesStack;
+ }
+
/**
* Tells whether both the calling package and the called package are vendor
* packages.
@@ -178,14 +199,8 @@ class Deprecation
return self::TYPE_UNDETERMINED;
}
$erroringFile = $erroringPackage = null;
- foreach ($this->trace as $line) {
- if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
- continue;
- }
- if (!isset($line['file'])) {
- continue;
- }
- $file = $line['file'];
+
+ foreach ($this->getOriginalFilesStack() as $file) {
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
continue;
}
diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
index d59b2d9337..af3f688d5d 100644
--- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
+++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php
@@ -11,12 +11,32 @@
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
+use Composer\Autoload\ClassLoader;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
+use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV5;
class DeprecationTest extends TestCase
{
+ public static function setUpBeforeClass(): void
+ {
+ $vendorDir = self::getVendorDir();
+
+ mkdir($vendorDir.'/myfakevendor/myfakepackage1', 0777, true);
+ mkdir($vendorDir.'/myfakevendor/myfakepackage2');
+ touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php');
+ touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php');
+ touch($vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php');
+ }
+
+ private static function getVendorDir(): string
+ {
+ $reflection = new \ReflectionClass(ClassLoader::class);
+
+ return \dirname($reflection->getFileName(), 2);
+ }
+
public function testItCanDetermineTheClassWhereTheDeprecationHappened()
{
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
@@ -118,12 +138,135 @@ class DeprecationTest extends TestCase
$this->assertTrue($deprecation->isMuted());
}
+ public function providerGetTypeDetectsSelf(): array
+ {
+ foreach (get_declared_classes() as $class) {
+ if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
+ $r = new \ReflectionClass($class);
+ $v = \dirname(\dirname($r->getFileName()));
+ if (file_exists($v.'/composer/installed.json')) {
+ $loader = require $v.'/autoload.php';
+ $reflection = new \ReflectionClass($loader);
+ $prop = $reflection->getProperty('prefixDirsPsr4');
+ $prop->setAccessible(true);
+ $currentValue = $prop->getValue($loader);
+ $currentValue['Symfony\\Bridge\\PhpUnit\\'] = [realpath(__DIR__.'/../..')];
+ $prop->setValue($loader, $currentValue);
+ }
+ }
+ }
+
+ return [
+ 'not_from_vendors_file' => [Deprecation::TYPE_SELF, '', 'MyClass1', ''],
+ 'nonexistent_file' => [Deprecation::TYPE_UNDETERMINED, '', 'MyClass1', 'dummy_vendor_path'],
+ 'serialized_trace_with_nonexistent_triggering_file' => [
+ Deprecation::TYPE_UNDETERMINED,
+ serialize([
+ 'class' => '',
+ 'method' => '',
+ 'deprecation' => '',
+ 'triggering_file' => 'dummy_vendor_path',
+ 'files_stack' => [],
+ ]),
+ SymfonyTestsListenerForV5::class,
+ '',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider providerGetTypeDetectsSelf
+ */
+ public function testGetTypeDetectsSelf(string $expectedType, string $message, string $traceClass, string $file): void
+ {
+ $trace = [
+ ['class' => 'MyClass1', 'function' => 'myMethod'],
+ ['class' => $traceClass, 'function' => 'myMethod'],
+ ];
+ $deprecation = new Deprecation($message, $trace, $file);
+ $this->assertEquals($expectedType, $deprecation->getType());
+ }
+
+ public function providerGetTypeUsesRightTrace(): array
+ {
+ $vendorDir = self::getVendorDir();
+
+ return [
+ 'no_file_in_stack' => [Deprecation::TYPE_DIRECT, '', [['function' => 'myfunc1'], ['function' => 'myfunc2']]],
+ 'files_in_stack_from_various_packages' => [
+ Deprecation::TYPE_INDIRECT,
+ '',
+ [
+ ['function' => 'myfunc1', 'file' => $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php'],
+ ['function' => 'myfunc2', 'file' => $vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php'],
+ ],
+ ],
+ 'serialized_stack_files_from_same_package' => [
+ Deprecation::TYPE_DIRECT,
+ serialize([
+ 'deprecation' => 'My deprecation message',
+ 'class' => 'MyClass',
+ 'method' => 'myMethod',
+ 'files_stack' => [
+ $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php',
+ $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php',
+ ],
+ ]),
+ [['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']],
+ ],
+ 'serialized_stack_files_from_various_packages' => [
+ Deprecation::TYPE_INDIRECT,
+ serialize([
+ 'deprecation' => 'My deprecation message',
+ 'class' => 'MyClass',
+ 'method' => 'myMethod',
+ 'files_stack' => [
+ $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php',
+ $vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php',
+ ],
+ ]),
+ [['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider providerGetTypeUsesRightTrace
+ */
+ public function testGetTypeUsesRightTrace(string $expectedType, string $message, array $trace): void
+ {
+ $deprecation = new Deprecation(
+ $message,
+ $trace,
+ self::getVendorDir().'/myfakevendor/myfakepackage2/MyFakeFile.php'
+ );
+ $this->assertEquals($expectedType, $deprecation->getType());
+ }
+
/**
* This method is here to simulate the extra level from the piece of code
- * triggering an error to the error handler
+ * triggering an error to the error handler.
*/
public function debugBacktrace(): array
{
return debug_backtrace();
}
+
+ private static function removeDir($dir): void
+ {
+ $files = glob($dir.'/*');
+ foreach ($files as $file) {
+ if (is_file($file)) {
+ unlink($file);
+ } else {
+ self::removeDir($file);
+ }
+ }
+ rmdir($dir);
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::removeDir(self::getVendorDir().'/myfakevendor');
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index f4bddfd843..228b62727c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -1265,7 +1265,7 @@ class Configuration implements ConfigurationInterface
if (!\is_array($config)) {
return [];
}
- if (!isset($config['host'])) {
+ if (!isset($config['host'], $config['value']) || \count($config) > 2) {
return $config;
}
@@ -1374,7 +1374,7 @@ class Configuration implements ConfigurationInterface
if (!\is_array($config)) {
return [];
}
- if (!isset($config['key'])) {
+ if (!isset($config['key'], $config['value']) || \count($config) > 2) {
return $config;
}
@@ -1404,7 +1404,7 @@ class Configuration implements ConfigurationInterface
if (!\is_array($config)) {
return [];
}
- if (!isset($config['host'])) {
+ if (!isset($config['host'], $config['value']) || \count($config) > 2) {
return $config;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_xml_key.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_xml_key.php
new file mode 100644
index 0000000000..64778c6156
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_xml_key.php
@@ -0,0 +1,22 @@
+loadFromExtension('framework', [
+ 'http_client' => [
+ 'default_options' => [
+ 'resolve' => [
+ 'host' => '127.0.0.1',
+ ],
+ ],
+ 'scoped_clients' => [
+ 'foo' => [
+ 'base_uri' => 'http://example.com',
+ 'query' => [
+ 'key' => 'foo',
+ ],
+ 'resolve' => [
+ 'host' => '127.0.0.1',
+ ],
+ ],
+ ],
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_xml_key.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_xml_key.xml
new file mode 100644
index 0000000000..95ef0737f8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_xml_key.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ 127.0.0.1
+
+
+ foo
+ 127.0.0.1
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_xml_key.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_xml_key.yml
new file mode 100644
index 0000000000..dc87555a90
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_xml_key.yml
@@ -0,0 +1,12 @@
+framework:
+ http_client:
+ default_options:
+ resolve:
+ host: 127.0.0.1
+ scoped_clients:
+ foo:
+ base_uri: http://example.com
+ query:
+ key: foo
+ resolve:
+ host: 127.0.0.1
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 0a54ebacfc..0ee3b892aa 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -1358,6 +1358,21 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertSame($expected, $container->getDefinition('foo')->getArgument(2));
}
+ public function testHttpClientWithQueryParameterKey()
+ {
+ $container = $this->createContainerFromFile('http_client_xml_key');
+
+ $expected = [
+ 'key' => 'foo',
+ ];
+ $this->assertSame($expected, $container->getDefinition('foo')->getArgument(2)['query']);
+
+ $expected = [
+ 'host' => '127.0.0.1',
+ ];
+ $this->assertSame($expected, $container->getDefinition('foo')->getArgument(2)['resolve']);
+ }
+
public function testHttpClientFullDefaultOptions()
{
$container = $this->createContainerFromFile('http_client_full_default_options');
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php
index 9b3760b497..1a2c829854 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php
@@ -54,78 +54,81 @@ trait PriorityTaggedServiceTrait
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
$class = $r = null;
- $priority = 0;
- if (isset($attributes[0]['priority'])) {
- $priority = $attributes[0]['priority'];
- } elseif ($defaultPriorityMethod) {
- $class = $container->getDefinition($serviceId)->getClass();
- $class = $container->getParameterBag()->resolveValue($class) ?: null;
- if (($r = $container->getReflectionClass($class)) && $r->hasMethod($defaultPriorityMethod)) {
- if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
- }
+ $defaultPriority = null;
+ $defaultIndex = null;
- if (!$rm->isPublic()) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
- }
+ foreach ($attributes as $attribute) {
+ $index = $priority = null;
- $priority = $rm->invoke(null);
+ if (isset($attribute['priority'])) {
+ $priority = $attribute['priority'];
+ } elseif (null === $defaultPriority && $defaultPriorityMethod) {
+ $class = $container->getDefinition($serviceId)->getClass();
+ $class = $container->getParameterBag()->resolveValue($class) ?: null;
- if (!\is_int($priority)) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer, got %s: tag "%s" on service "%s".', $class, $defaultPriorityMethod, \gettype($priority), $tagName, $serviceId));
+ if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultPriorityMethod)) {
+ if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
+ }
+
+ if (!$rm->isPublic()) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
+ }
+
+ $defaultPriority = $rm->invoke(null);
+
+ if (!\is_int($defaultPriority)) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer, got %s: tag "%s" on service "%s".', $class, $defaultPriorityMethod, \gettype($priority), $tagName, $serviceId));
+ }
}
}
- }
- if (null === $indexAttribute && !$needsIndexes) {
- $services[$priority][] = new Reference($serviceId);
+ $priority = $priority ?? $defaultPriority ?? 0;
- continue;
- }
+ if (null !== $indexAttribute && isset($attribute[$indexAttribute])) {
+ $index = $attribute[$indexAttribute];
+ } elseif (null === $defaultIndex && null === $indexAttribute && !$needsIndexes) {
+ // With partially associative array, insertion to get next key is simpler.
+ $services[$priority][] = null;
+ end($services[$priority]);
+ $defaultIndex = key($services[$priority]);
+ } elseif (null === $defaultIndex && $defaultIndexMethod) {
+ $class = $container->getDefinition($serviceId)->getClass();
+ $class = $container->getParameterBag()->resolveValue($class) ?: null;
- if (!$class) {
- $class = $container->getDefinition($serviceId)->getClass();
- $class = $container->getParameterBag()->resolveValue($class) ?: null;
- }
+ if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultIndexMethod)) {
+ if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
+ }
- if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) {
- $services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]);
+ if (!$rm->isPublic()) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
+ }
- continue;
- }
+ $defaultIndex = $rm->invoke(null);
- if (!$r && !$r = $container->getReflectionClass($class)) {
- throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
- }
+ if (!\is_string($defaultIndex)) {
+ throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($defaultIndex), $tagName, $serviceId, $indexAttribute));
+ }
+ }
- $class = $r->name;
-
- if (!$r->hasMethod($defaultIndexMethod)) {
- if ($needsIndexes) {
- $services[$priority][$serviceId] = new TypedReference($serviceId, $class);
-
- continue;
+ $defaultIndex = $defaultIndex ?? $serviceId;
}
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
+ $index = $index ?? $defaultIndex;
+
+ $reference = null;
+ if (!$class || 'stdClass' === $class) {
+ $reference = new Reference($serviceId);
+ } elseif ($index === $serviceId) {
+ $reference = new TypedReference($serviceId, $class);
+ } else {
+ $reference = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, \is_string($index) ? $index : null);
+ }
+
+ $services[$priority][$index] = $reference;
}
-
- if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
- }
-
- if (!$rm->isPublic()) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
- }
-
- $key = $rm->invoke(null);
-
- if (!\is_string($key)) {
- throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute));
- }
-
- $services[$priority][$key] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $key);
}
if ($services) {
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
index bd25e3f0ec..987605f98f 100644
--- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
+++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
@@ -126,9 +126,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
}
if (false !== $i || 'string' !== $prefix) {
- if (null === $env = $getEnv($name)) {
- return null;
- }
+ $env = $getEnv($name);
} elseif (isset($_ENV[$name])) {
$env = $_ENV[$name];
} elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
@@ -173,12 +171,18 @@ class EnvVarProcessor implements EnvVarProcessorInterface
throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name));
}
- if (null === $env = $this->container->getParameter("env($name)")) {
- return null;
- }
+ $env = $this->container->getParameter("env($name)");
}
}
+ if (null === $env) {
+ if (!isset($this->getProvidedTypes()[$prefix])) {
+ throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix));
+ }
+
+ return null;
+ }
+
if (!is_scalar($env)) {
throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to %s.', $name, $prefix));
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
index 7d4f01a265..f6c255484a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
@@ -314,6 +314,32 @@ class IntegrationTest extends TestCase
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
}
+ public function testTaggedIteratorWithMultipleIndexAttribute()
+ {
+ $container = new ContainerBuilder();
+ $container->register(BarTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar', ['foo' => 'bar'])
+ ->addTag('foo_bar', ['foo' => 'bar_duplicate'])
+ ;
+ $container->register(FooTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar')
+ ->addTag('foo_bar')
+ ;
+ $container->register(FooBarTaggedClass::class)
+ ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo'))
+ ->setPublic(true)
+ ;
+
+ $container->compile();
+
+ $s = $container->get(FooBarTaggedClass::class);
+
+ $param = iterator_to_array($s->getParam()->getIterator());
+ $this->assertSame(['bar' => $container->get(BarTagClass::class), 'bar_duplicate' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param);
+ }
+
public function testTaggedServiceWithDefaultPriorityMethod()
{
$container = new ContainerBuilder();
@@ -350,7 +376,7 @@ class IntegrationTest extends TestCase
->addTag('foo_bar')
;
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
- ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo')))
+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', null, true)))
->setPublic(true)
;
@@ -369,6 +395,40 @@ class IntegrationTest extends TestCase
$this->assertSame(['bar' => $container->get('bar_tag'), 'foo_tag_class' => $container->get('foo_tag')], $same);
}
+ public function testTaggedServiceLocatorWithMultipleIndexAttribute()
+ {
+ $container = new ContainerBuilder();
+ $container->register('bar_tag', BarTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar', ['foo' => 'bar'])
+ ->addTag('foo_bar', ['foo' => 'bar_duplicate'])
+ ;
+ $container->register('foo_tag', FooTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar')
+ ->addTag('foo_bar')
+ ;
+ $container->register('foo_bar_tagged', FooBarTaggedClass::class)
+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', null, true)))
+ ->setPublic(true)
+ ;
+
+ $container->compile();
+
+ $s = $container->get('foo_bar_tagged');
+
+ /** @var ServiceLocator $serviceLocator */
+ $serviceLocator = $s->getParam();
+ $this->assertTrue($s->getParam() instanceof ServiceLocator, sprintf('Wrong instance, should be an instance of ServiceLocator, %s given', \is_object($serviceLocator) ? \get_class($serviceLocator) : \gettype($serviceLocator)));
+
+ $same = [
+ 'bar' => $serviceLocator->get('bar'),
+ 'bar_duplicate' => $serviceLocator->get('bar_duplicate'),
+ 'foo_tag_class' => $serviceLocator->get('foo_tag_class'),
+ ];
+ $this->assertSame(['bar' => $container->get('bar_tag'), 'bar_duplicate' => $container->get('bar_tag'), 'foo_tag_class' => $container->get('foo_tag')], $same);
+ }
+
public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod()
{
$container = new ContainerBuilder();
@@ -381,7 +441,7 @@ class IntegrationTest extends TestCase
->addTag('foo_bar', ['foo' => 'foo'])
;
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
- ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar')))
+ ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar', true)))
->setPublic(true)
;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
index df329b4f7e..313bce5973 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
@@ -9,6 +9,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
use Symfony\Component\DependencyInjection\EnvVarProcessor;
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
class EnvVarProcessorTest extends TestCase
{
@@ -595,4 +596,17 @@ CSV;
$this->assertSame(2, $index);
}
+
+ public function testGetEnvInvalidPrefixWithDefault()
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Unsupported env var prefix');
+ $processor = new EnvVarProcessor(new Container());
+
+ $processor->getEnv('unknown', 'default::FAKE', function ($name) {
+ $this->assertSame('default::FAKE', $name);
+
+ return null;
+ });
+ }
}
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php
index b6b3bef07e..79201f7f8a 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php
@@ -16,7 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\SmtpEnvelope;
-use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
+use Symfony\Component\Mailer\Transport\AbstractHttpTransport;
use Symfony\Component\Mime\Address;
use Symfony\Contracts\HttpClient\HttpClientInterface;
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php
index dd2851154e..cfdc30bb78 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php
@@ -57,7 +57,7 @@ class MandrillHttpTransportTest extends TestCase
$body = json_decode($options['body'], true);
$message = $body['raw_message'];
$this->assertSame('KEY', $body['key']);
- $this->assertSame('Saif Eddin ', $body['to'][0]);
+ $this->assertSame('saif.gmati@symfony.com', $body['to'][0]);
$this->assertSame('Fabien ', $body['from_email']);
$this->assertStringContainsString('Subject: Hello!', $message);
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
index 09e728862c..6ead154906 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php
@@ -47,7 +47,9 @@ class MandrillHttpTransport extends AbstractHttpTransport
$response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/api/1.0/messages/send-raw.json', [
'json' => [
'key' => $this->key,
- 'to' => $this->getRecipients($envelope->getRecipients()),
+ 'to' => array_map(function (Address $recipient): string {
+ return $recipient->getAddress();
+ }, $envelope->getRecipients()),
'from_email' => $envelope->getSender()->toString(),
'raw_message' => $message->toString(),
],
@@ -71,14 +73,4 @@ class MandrillHttpTransport extends AbstractHttpTransport
{
return ($this->host ?: self::HOST).($this->port ? ':'.$this->port : '');
}
-
- /**
- * @return string[]
- */
- private function getRecipients(Envelope $envelope): array
- {
- return array_map(function (Address $recipient): string {
- return $recipient->getAddress();
- }, $envelope->getRecipients());
- }
}