Merge branch '5.2' into 5.x
* 5.2: make fabbot happy use correct spelling when accessing the SMTP php.ini value Fix issue 40507: Tabs as separators between tokens [Cache] phpredis: Added full TLS support for RedisCluster [DependencyInjection][AliasDeprecatedPublicServicesPass] Noop when the service is private
This commit is contained in:
commit
a9d582d681
48
src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php
Normal file
48
src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Cache\Traits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as
|
||||||
|
* individual \Redis objects.
|
||||||
|
*
|
||||||
|
* Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)'
|
||||||
|
* according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands
|
||||||
|
*
|
||||||
|
* @author Jack Thomas <jack.thomas@solidalpha.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class RedisClusterNodeProxy
|
||||||
|
{
|
||||||
|
private $host;
|
||||||
|
private $redis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \RedisCluster|RedisClusterProxy $redis
|
||||||
|
*/
|
||||||
|
public function __construct(array $host, $redis)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
$this->redis = $redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call(string $method, array $args)
|
||||||
|
{
|
||||||
|
return $this->redis->{$method}($this->host, ...$args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scan(&$iIterator, $strPattern = null, $iCount = null)
|
||||||
|
{
|
||||||
|
return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount);
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,7 @@ trait RedisTrait
|
|||||||
'redis_sentinel' => null,
|
'redis_sentinel' => null,
|
||||||
'dbindex' => 0,
|
'dbindex' => 0,
|
||||||
'failover' => 'none',
|
'failover' => 'none',
|
||||||
|
'ssl' => null, // see https://php.net/context.ssl
|
||||||
];
|
];
|
||||||
private $redis;
|
private $redis;
|
||||||
private $marshaller;
|
private $marshaller;
|
||||||
@ -202,7 +203,7 @@ trait RedisTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout']);
|
@$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ['stream' => $params['ssl'] ?? null]);
|
||||||
|
|
||||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||||
$isConnected = $redis->isConnected();
|
$isConnected = $redis->isConnected();
|
||||||
@ -265,7 +266,7 @@ trait RedisTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '');
|
$redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', $params['ssl'] ?? null);
|
||||||
} catch (\RedisClusterException $e) {
|
} catch (\RedisClusterException $e) {
|
||||||
throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
|
throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage());
|
||||||
}
|
}
|
||||||
@ -311,7 +312,7 @@ trait RedisTrait
|
|||||||
}
|
}
|
||||||
$params['exceptions'] = false;
|
$params['exceptions'] = false;
|
||||||
|
|
||||||
$redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions));
|
$redis = new $class($hosts, array_diff_key($params, array_diff_key(self::$defaultConnectionOptions, ['ssl' => null])));
|
||||||
if (isset($params['redis_sentinel'])) {
|
if (isset($params['redis_sentinel'])) {
|
||||||
$redis->getConnection()->setSentinelTimeout($params['timeout']);
|
$redis->getConnection()->setSentinelTimeout($params['timeout']);
|
||||||
}
|
}
|
||||||
@ -558,8 +559,7 @@ trait RedisTrait
|
|||||||
} elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) {
|
} elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) {
|
||||||
$hosts = [];
|
$hosts = [];
|
||||||
foreach ($this->redis->_masters() as $host) {
|
foreach ($this->redis->_masters() as $host) {
|
||||||
$hosts[] = $h = new \Redis();
|
$hosts[] = new RedisClusterNodeProxy($host, $this->redis);
|
||||||
$h->connect($host[0], $host[1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ final class AliasDeprecatedPublicServicesPass extends AbstractRecursivePass
|
|||||||
|
|
||||||
$definition = $container->getDefinition($id);
|
$definition = $container->getDefinition($id);
|
||||||
if (!$definition->isPublic() || $definition->isPrivate()) {
|
if (!$definition->isPublic() || $definition->isPrivate()) {
|
||||||
throw new InvalidArgumentException(sprintf('The "%s" service is private: it cannot have the "%s" tag.', $id, $this->tagName));
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$container
|
$container
|
||||||
|
@ -59,14 +59,13 @@ final class AliasDeprecatedPublicServicesPassTest extends TestCase
|
|||||||
|
|
||||||
public function testProcessWithNonPublicService()
|
public function testProcessWithNonPublicService()
|
||||||
{
|
{
|
||||||
$this->expectException(InvalidArgumentException::class);
|
|
||||||
$this->expectExceptionMessage('The "foo" service is private: it cannot have the "container.private" tag.');
|
|
||||||
|
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
$container
|
$container
|
||||||
->register('foo')
|
->register('foo')
|
||||||
->addTag('container.private', ['package' => 'foo/bar', 'version' => '1.2']);
|
->addTag('container.private', ['package' => 'foo/bar', 'version' => '1.2']);
|
||||||
|
|
||||||
(new AliasDeprecatedPublicServicesPass())->process($container);
|
(new AliasDeprecatedPublicServicesPass())->process($container);
|
||||||
|
|
||||||
|
$this->assertTrue($container->hasDefinition('foo'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ EOT;
|
|||||||
{
|
{
|
||||||
self::$fakeConfiguration = [
|
self::$fakeConfiguration = [
|
||||||
'sendmail_path' => $sendmailPath,
|
'sendmail_path' => $sendmailPath,
|
||||||
'smtp' => $smtp,
|
'SMTP' => $smtp,
|
||||||
'smtp_port' => $smtpPort,
|
'smtp_port' => $smtpPort,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ final class NativeTransportFactory extends AbstractTransportFactory
|
|||||||
|
|
||||||
// Only for windows hosts; at this point non-windows
|
// Only for windows hosts; at this point non-windows
|
||||||
// host have already thrown an exception or returned a transport
|
// host have already thrown an exception or returned a transport
|
||||||
$host = ini_get('smtp');
|
$host = ini_get('SMTP');
|
||||||
$port = (int) ini_get('smtp_port');
|
$port = (int) ini_get('smtp_port');
|
||||||
|
|
||||||
if (!$host || !$port) {
|
if (!$host || !$port) {
|
||||||
|
@ -212,7 +212,7 @@ class Parser
|
|||||||
array_pop($this->refsBeingParsed);
|
array_pop($this->refsBeingParsed);
|
||||||
}
|
}
|
||||||
} elseif (
|
} elseif (
|
||||||
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:( ++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
|
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(( |\t)++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
|
||||||
&& (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"]))
|
&& (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"]))
|
||||||
) {
|
) {
|
||||||
if ($context && 'sequence' == $context) {
|
if ($context && 'sequence' == $context) {
|
||||||
@ -230,7 +230,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!\is_string($key) && !\is_int($key)) {
|
if (!\is_string($key) && !\is_int($key)) {
|
||||||
throw new ParseException(sprintf('%s keys are not supported. Quote your evaluable mapping keys instead.', is_numeric($key) ? 'Numeric' : 'Non-string'), $this->getRealCurrentLineNb() + 1, $this->currentLine);
|
throw new ParseException((is_numeric($key) ? 'Numeric' : 'Non-string').' keys are not supported. Quote your evaluable mapping keys instead.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert float keys to strings, to avoid being converted to integers by PHP
|
// Convert float keys to strings, to avoid being converted to integers by PHP
|
||||||
@ -245,7 +245,7 @@ class Parser
|
|||||||
$refName = substr(rtrim($values['value']), 1);
|
$refName = substr(rtrim($values['value']), 1);
|
||||||
if (!\array_key_exists($refName, $this->refs)) {
|
if (!\array_key_exists($refName, $this->refs)) {
|
||||||
if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
|
if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
|
||||||
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$refName])), $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
|
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
|
||||||
@ -732,7 +732,7 @@ class Parser
|
|||||||
|
|
||||||
if (!\array_key_exists($value, $this->refs)) {
|
if (!\array_key_exists($value, $this->refs)) {
|
||||||
if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
|
if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
|
||||||
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$value])), $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
|
||||||
@ -1225,7 +1225,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
} while ($this->moveToNextLine());
|
} while ($this->moveToNextLine());
|
||||||
|
|
||||||
throw new ParseException('Malformed inline YAML string');
|
throw new ParseException('Malformed inline YAML string.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function lexUnquotedString(int &$cursor): string
|
private function lexUnquotedString(int &$cursor): string
|
||||||
@ -1296,7 +1296,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
} while ($this->moveToNextLine());
|
} while ($this->moveToNextLine());
|
||||||
|
|
||||||
throw new ParseException('Malformed inline YAML string');
|
throw new ParseException('Malformed inline YAML string.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function consumeWhitespaces(int &$cursor): bool
|
private function consumeWhitespaces(int &$cursor): bool
|
||||||
|
@ -52,26 +52,67 @@ class ParserTest extends TestCase
|
|||||||
return $this->loadTestsFromFixtureFiles('nonStringKeys.yml');
|
return $this->loadTestsFromFixtureFiles('nonStringKeys.yml');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTabsInYaml()
|
/**
|
||||||
|
* @dataProvider invalidIndentation
|
||||||
|
*/
|
||||||
|
public function testTabsAsIndentationInYaml(string $given, string $expectedMessage)
|
||||||
{
|
{
|
||||||
// test tabs in YAML
|
$this->expectException(ParseException::class);
|
||||||
$yamls = [
|
$this->expectExceptionMessage($expectedMessage);
|
||||||
"foo:\n bar",
|
$this->parser->parse($given);
|
||||||
"foo:\n bar",
|
}
|
||||||
"foo:\n bar",
|
|
||||||
"foo:\n bar",
|
public function invalidIndentation(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
"foo:\n\tbar",
|
||||||
|
"A YAML file cannot contain tabs as indentation at line 2 (near \"\tbar\").",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo:\n \tbar",
|
||||||
|
"A YAML file cannot contain tabs as indentation at line 2 (near \"\tbar\").",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo:\n\t bar",
|
||||||
|
"A YAML file cannot contain tabs as indentation at line 2 (near \"\t bar\").",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo:\n \t bar",
|
||||||
|
"A YAML file cannot contain tabs as indentation at line 2 (near \"\t bar\").",
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($yamls as $yaml) {
|
/**
|
||||||
try {
|
* @dataProvider validTokenSeparators
|
||||||
$this->parser->parse($yaml);
|
*/
|
||||||
|
public function testValidTokenSeparation(string $given, array $expected)
|
||||||
|
{
|
||||||
|
$actual = $this->parser->parse($given);
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
|
||||||
$this->fail('YAML files must not contain tabs');
|
public function validTokenSeparators(): array
|
||||||
} catch (\Exception $e) {
|
{
|
||||||
$this->assertInstanceOf(\Exception::class, $e, 'YAML files must not contain tabs');
|
return [
|
||||||
$this->assertEquals('A YAML file cannot contain tabs as indentation at line 2 (near "'.strpbrk($yaml, "\t").'").', $e->getMessage(), 'YAML files must not contain tabs');
|
[
|
||||||
}
|
'foo: bar',
|
||||||
}
|
['foo' => 'bar'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo:\tbar",
|
||||||
|
['foo' => 'bar'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo: \tbar",
|
||||||
|
['foo' => 'bar'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"foo:\t bar",
|
||||||
|
['foo' => 'bar'],
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEndOfTheDocumentMarker()
|
public function testEndOfTheDocumentMarker()
|
||||||
|
Reference in New Issue
Block a user