Merge branch '5.0'
* 5.0: [Mailer] fix typos [Messenger] fix typo [DI] Unknown env prefix not regornized as such [DI] Fix support for multiple tags for locators and iterators [PhpUnitBridge] Fix some errors when using serialized deprecations Fix HTTP client config handling
This commit is contained in:
commit
0db2b0a4bc
@ -96,7 +96,19 @@ class DeprecationErrorHandler
|
|||||||
return \call_user_func(self::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context);
|
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;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -44,6 +44,8 @@ class Deprecation
|
|||||||
*/
|
*/
|
||||||
private static $internalPaths = [];
|
private static $internalPaths = [];
|
||||||
|
|
||||||
|
private $originalFilesStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param string $file
|
* @param string $file
|
||||||
@ -64,6 +66,7 @@ class Deprecation
|
|||||||
$this->message = $parsedMsg['deprecation'];
|
$this->message = $parsedMsg['deprecation'];
|
||||||
$this->originClass = $parsedMsg['class'];
|
$this->originClass = $parsedMsg['class'];
|
||||||
$this->originMethod = $parsedMsg['method'];
|
$this->originMethod = $parsedMsg['method'];
|
||||||
|
$this->originalFilesStack = $parsedMsg['files_stack'];
|
||||||
// If the deprecation has been triggered via
|
// If the deprecation has been triggered via
|
||||||
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
|
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
|
||||||
// then we need to use the serialized information to determine
|
// 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);
|
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
|
* Tells whether both the calling package and the called package are vendor
|
||||||
* packages.
|
* packages.
|
||||||
@ -178,14 +199,8 @@ class Deprecation
|
|||||||
return self::TYPE_UNDETERMINED;
|
return self::TYPE_UNDETERMINED;
|
||||||
}
|
}
|
||||||
$erroringFile = $erroringPackage = null;
|
$erroringFile = $erroringPackage = null;
|
||||||
foreach ($this->trace as $line) {
|
|
||||||
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
|
foreach ($this->getOriginalFilesStack() as $file) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!isset($line['file'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$file = $line['file'];
|
|
||||||
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
|
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,32 @@
|
|||||||
|
|
||||||
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
|
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
|
||||||
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
|
||||||
|
use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV5;
|
||||||
|
|
||||||
class DeprecationTest extends TestCase
|
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()
|
public function testItCanDetermineTheClassWhereTheDeprecationHappened()
|
||||||
{
|
{
|
||||||
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
|
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
|
||||||
@ -118,12 +138,135 @@ class DeprecationTest extends TestCase
|
|||||||
$this->assertTrue($deprecation->isMuted());
|
$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
|
* 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
|
public function debugBacktrace(): array
|
||||||
{
|
{
|
||||||
return debug_backtrace();
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1279,7 +1279,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
if (!\is_array($config)) {
|
if (!\is_array($config)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!isset($config['host'])) {
|
if (!isset($config['host'], $config['value']) || \count($config) > 2) {
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,7 +1388,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
if (!\is_array($config)) {
|
if (!\is_array($config)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!isset($config['key'])) {
|
if (!isset($config['key'], $config['value']) || \count($config) > 2) {
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1418,7 +1418,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
if (!\is_array($config)) {
|
if (!\is_array($config)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!isset($config['host'])) {
|
if (!isset($config['host'], $config['value']) || \count($config) > 2) {
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$container->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',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:framework="http://symfony.com/schema/dic/symfony"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
|
||||||
|
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||||
|
|
||||||
|
<framework:config>
|
||||||
|
<framework:http-client>
|
||||||
|
<framework:default-options>
|
||||||
|
<framework:resolve host="host">127.0.0.1</framework:resolve>
|
||||||
|
</framework:default-options>
|
||||||
|
<framework:scoped-client name="foo" base-uri="http://example.com">
|
||||||
|
<framework:query key="key">foo</framework:query>
|
||||||
|
<framework:resolve host="host">127.0.0.1</framework:resolve>
|
||||||
|
</framework:scoped-client>
|
||||||
|
</framework:http-client>
|
||||||
|
</framework:config>
|
||||||
|
</container>
|
@ -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
|
@ -1360,6 +1360,21 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
$this->assertSame($expected, $container->getDefinition('foo')->getArgument(2));
|
$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()
|
public function testHttpClientFullDefaultOptions()
|
||||||
{
|
{
|
||||||
$container = $this->createContainerFromFile('http_client_full_default_options');
|
$container = $this->createContainerFromFile('http_client_full_default_options');
|
||||||
|
@ -54,78 +54,81 @@ trait PriorityTaggedServiceTrait
|
|||||||
|
|
||||||
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
||||||
$class = $r = null;
|
$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)) {
|
$defaultPriority = null;
|
||||||
if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
|
$defaultIndex = null;
|
||||||
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$rm->isPublic()) {
|
foreach ($attributes as $attribute) {
|
||||||
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
|
$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)) {
|
if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultPriorityMethod)) {
|
||||||
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 (!($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) {
|
$priority = $priority ?? $defaultPriority ?? 0;
|
||||||
$services[$priority][] = new Reference($serviceId);
|
|
||||||
|
|
||||||
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) {
|
if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultIndexMethod)) {
|
||||||
$class = $container->getDefinition($serviceId)->getClass();
|
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
|
||||||
$class = $container->getParameterBag()->resolveValue($class) ?: null;
|
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])) {
|
if (!$rm->isPublic()) {
|
||||||
$services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]);
|
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)) {
|
if (!\is_string($defaultIndex)) {
|
||||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
|
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;
|
$defaultIndex = $defaultIndex ?? $serviceId;
|
||||||
|
|
||||||
if (!$r->hasMethod($defaultIndexMethod)) {
|
|
||||||
if ($needsIndexes) {
|
|
||||||
$services[$priority][$serviceId] = new TypedReference($serviceId, $class);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if ($services) {
|
||||||
|
@ -126,9 +126,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (false !== $i || 'string' !== $prefix) {
|
if (false !== $i || 'string' !== $prefix) {
|
||||||
if (null === $env = $getEnv($name)) {
|
$env = $getEnv($name);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} elseif (isset($_ENV[$name])) {
|
} elseif (isset($_ENV[$name])) {
|
||||||
$env = $_ENV[$name];
|
$env = $_ENV[$name];
|
||||||
} elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
|
} 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));
|
throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $env = $this->container->getParameter("env($name)")) {
|
$env = $this->container->getParameter("env($name)");
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null === $env) {
|
||||||
|
if (!isset($this->getProvidedTypes()[$prefix])) {
|
||||||
|
throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_scalar($env)) {
|
if (!is_scalar($env)) {
|
||||||
throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to %s.', $name, $prefix));
|
throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to %s.', $name, $prefix));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
$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()
|
public function testTaggedServiceWithDefaultPriorityMethod()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
@ -350,7 +376,7 @@ class IntegrationTest extends TestCase
|
|||||||
->addTag('foo_bar')
|
->addTag('foo_bar')
|
||||||
;
|
;
|
||||||
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
|
$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)
|
->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);
|
$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()
|
public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
@ -381,7 +441,7 @@ class IntegrationTest extends TestCase
|
|||||||
->addTag('foo_bar', ['foo' => 'foo'])
|
->addTag('foo_bar', ['foo' => 'foo'])
|
||||||
;
|
;
|
||||||
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
|
$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)
|
->setPublic(true)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|||||||
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
|
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
|
||||||
use Symfony\Component\DependencyInjection\EnvVarProcessor;
|
use Symfony\Component\DependencyInjection\EnvVarProcessor;
|
||||||
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
||||||
|
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
|
|
||||||
class EnvVarProcessorTest extends TestCase
|
class EnvVarProcessorTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -595,4 +596,17 @@ CSV;
|
|||||||
|
|
||||||
$this->assertSame(2, $index);
|
$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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\TransportException;
|
||||||
use Symfony\Component\Mailer\SentMessage;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
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\Component\Mime\Address;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
|
@ -49,7 +49,9 @@ class MandrillHttpTransport extends AbstractHttpTransport
|
|||||||
$response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/api/1.0/messages/send-raw.json', [
|
$response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/api/1.0/messages/send-raw.json', [
|
||||||
'json' => [
|
'json' => [
|
||||||
'key' => $this->key,
|
'key' => $this->key,
|
||||||
'to' => $this->getRecipients($envelope),
|
'to' => array_map(function (Address $recipient): string {
|
||||||
|
return $recipient->getAddress();
|
||||||
|
}, $envelope->getRecipients()),
|
||||||
'from_email' => $envelope->getSender()->toString(),
|
'from_email' => $envelope->getSender()->toString(),
|
||||||
'raw_message' => $message->toString(),
|
'raw_message' => $message->toString(),
|
||||||
],
|
],
|
||||||
@ -73,14 +75,4 @@ class MandrillHttpTransport extends AbstractHttpTransport
|
|||||||
{
|
{
|
||||||
return ($this->host ?: self::HOST).($this->port ? ':'.$this->port : '');
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user