Merge branch '4.4'
* 4.4: [Messenger] Perform no deep merging of bus middleware [HttpFoundation] Added possibility to configure expiration time in redis session handler [FrameworkBundle] Remove project dir from Translator cache vary scanned directories [HttpFoundation] Allow redirecting to URLs that contain a semicolon Drop useless executable bit [DoctrineBridge] Improve queries parameters display in Profiler catch exceptions when using PDO directly [SecurityBundle] fix failing test
This commit is contained in:
commit
3d222c6cd5
@ -18,6 +18,8 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||
use Symfony\Component\VarDumper\Caster\Caster;
|
||||
use Symfony\Component\VarDumper\Cloner\Stub;
|
||||
|
||||
/**
|
||||
* DoctrineDataCollector.
|
||||
@ -117,6 +119,38 @@ class DoctrineDataCollector extends DataCollector
|
||||
return 'db';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCasters()
|
||||
{
|
||||
return parent::getCasters() + [
|
||||
ObjectParameter::class => static function (ObjectParameter $o, array $a, Stub $s): array {
|
||||
$s->class = $o->getClass();
|
||||
$s->value = $o->getObject();
|
||||
|
||||
$r = new \ReflectionClass($o->getClass());
|
||||
if ($f = $r->getFileName()) {
|
||||
$s->attr['file'] = $f;
|
||||
$s->attr['line'] = $r->getStartLine();
|
||||
} else {
|
||||
unset($s->attr['file']);
|
||||
unset($s->attr['line']);
|
||||
}
|
||||
|
||||
if ($error = $o->getError()) {
|
||||
return [Caster::PREFIX_VIRTUAL.'⚠' => $error->getMessage()];
|
||||
}
|
||||
|
||||
if ($o->isStringable()) {
|
||||
return [Caster::PREFIX_VIRTUAL.'__toString()' => (string) $o->getObject()];
|
||||
}
|
||||
|
||||
return [Caster::PREFIX_VIRTUAL.'⚠' => sprintf('Object of class "%s" could not be converted to string.', $o->getClass())];
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private function sanitizeQueries(string $connectionName, array $queries): array
|
||||
{
|
||||
foreach ($queries as $i => $query) {
|
||||
@ -129,6 +163,7 @@ class DoctrineDataCollector extends DataCollector
|
||||
private function sanitizeQuery(string $connectionName, array $query): array
|
||||
{
|
||||
$query['explainable'] = true;
|
||||
$query['runnable'] = true;
|
||||
if (null === $query['params']) {
|
||||
$query['params'] = [];
|
||||
}
|
||||
@ -139,6 +174,7 @@ class DoctrineDataCollector extends DataCollector
|
||||
$query['types'] = [];
|
||||
}
|
||||
foreach ($query['params'] as $j => $param) {
|
||||
$e = null;
|
||||
if (isset($query['types'][$j])) {
|
||||
// Transform the param according to the type
|
||||
$type = $query['types'][$j];
|
||||
@ -150,18 +186,19 @@ class DoctrineDataCollector extends DataCollector
|
||||
try {
|
||||
$param = $type->convertToDatabaseValue($param, $this->registry->getConnection($connectionName)->getDatabasePlatform());
|
||||
} catch (\TypeError $e) {
|
||||
// Error thrown while processing params, query is not explainable.
|
||||
$query['explainable'] = false;
|
||||
} catch (ConversionException $e) {
|
||||
$query['explainable'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list($query['params'][$j], $explainable) = $this->sanitizeParam($param);
|
||||
list($query['params'][$j], $explainable, $runnable) = $this->sanitizeParam($param, $e);
|
||||
if (!$explainable) {
|
||||
$query['explainable'] = false;
|
||||
}
|
||||
|
||||
if (!$runnable) {
|
||||
$query['runnable'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$query['params'] = $this->cloneVar($query['params']);
|
||||
@ -176,32 +213,33 @@ class DoctrineDataCollector extends DataCollector
|
||||
* indicating if the original value was kept (allowing to use the sanitized
|
||||
* value to explain the query).
|
||||
*/
|
||||
private function sanitizeParam($var): array
|
||||
private function sanitizeParam($var, ?\Throwable $error): array
|
||||
{
|
||||
if (\is_object($var)) {
|
||||
$className = \get_class($var);
|
||||
return [$o = new ObjectParameter($var, $error), false, $o->isStringable() && !$error];
|
||||
}
|
||||
|
||||
return method_exists($var, '__toString') ?
|
||||
[sprintf('/* Object(%s): */"%s"', $className, $var->__toString()), false] :
|
||||
[sprintf('/* Object(%s) */', $className), false];
|
||||
if ($error) {
|
||||
return ['⚠ '.$error->getMessage(), false, false];
|
||||
}
|
||||
|
||||
if (\is_array($var)) {
|
||||
$a = [];
|
||||
$original = true;
|
||||
$explainable = $runnable = true;
|
||||
foreach ($var as $k => $v) {
|
||||
list($value, $orig) = $this->sanitizeParam($v);
|
||||
$original = $original && $orig;
|
||||
list($value, $e, $r) = $this->sanitizeParam($v, null);
|
||||
$explainable = $explainable && $e;
|
||||
$runnable = $runnable && $r;
|
||||
$a[$k] = $value;
|
||||
}
|
||||
|
||||
return [$a, $original];
|
||||
return [$a, $explainable, $runnable];
|
||||
}
|
||||
|
||||
if (\is_resource($var)) {
|
||||
return [sprintf('/* Resource(%s) */', get_resource_type($var)), false];
|
||||
return [sprintf('/* Resource(%s) */', get_resource_type($var)), false, false];
|
||||
}
|
||||
|
||||
return [$var, true];
|
||||
return [$var, true, true];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
<?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\Bridge\Doctrine\DataCollector;
|
||||
|
||||
final class ObjectParameter
|
||||
{
|
||||
private $object;
|
||||
private $error;
|
||||
private $stringable;
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @param object $object
|
||||
*/
|
||||
public function __construct($object, ?\Throwable $error)
|
||||
{
|
||||
$this->object = $object;
|
||||
$this->error = $error;
|
||||
$this->stringable = \is_callable([$object, '__toString']);
|
||||
$this->class = \get_class($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object
|
||||
*/
|
||||
public function getObject()
|
||||
{
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
public function getError(): ?\Throwable
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function isStringable(): bool
|
||||
{
|
||||
return $this->stringable;
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
|
||||
class DoctrineDataCollectorTest extends TestCase
|
||||
{
|
||||
@ -74,7 +75,7 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
/**
|
||||
* @dataProvider paramProvider
|
||||
*/
|
||||
public function testCollectQueries($param, $types, $expected, $explainable)
|
||||
public function testCollectQueries($param, $types, $expected, $explainable, bool $runnable = true)
|
||||
{
|
||||
$queries = [
|
||||
['sql' => 'SELECT * FROM table1 WHERE field1 = ?1', 'params' => [$param], 'types' => $types, 'executionMS' => 1],
|
||||
@ -83,8 +84,19 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
$c->collect(new Request(), new Response());
|
||||
|
||||
$collectedQueries = $c->getQueries();
|
||||
$this->assertEquals($expected, $collectedQueries['default'][0]['params'][0]);
|
||||
|
||||
$collectedParam = $collectedQueries['default'][0]['params'][0];
|
||||
if ($collectedParam instanceof Data) {
|
||||
$dumper = new CliDumper($out = fopen('php://memory', 'r+b'));
|
||||
$dumper->setColors(false);
|
||||
$collectedParam->dump($dumper);
|
||||
$this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true));
|
||||
} else {
|
||||
$this->assertEquals($expected, $collectedParam);
|
||||
}
|
||||
|
||||
$this->assertEquals($explainable, $collectedQueries['default'][0]['explainable']);
|
||||
$this->assertSame($runnable, $collectedQueries['default'][0]['runnable']);
|
||||
}
|
||||
|
||||
public function testCollectQueryWithNoParams()
|
||||
@ -100,9 +112,11 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
$this->assertInstanceOf(Data::class, $collectedQueries['default'][0]['params']);
|
||||
$this->assertEquals([], $collectedQueries['default'][0]['params']->getValue());
|
||||
$this->assertTrue($collectedQueries['default'][0]['explainable']);
|
||||
$this->assertTrue($collectedQueries['default'][0]['runnable']);
|
||||
$this->assertInstanceOf(Data::class, $collectedQueries['default'][1]['params']);
|
||||
$this->assertEquals([], $collectedQueries['default'][1]['params']->getValue());
|
||||
$this->assertTrue($collectedQueries['default'][1]['explainable']);
|
||||
$this->assertTrue($collectedQueries['default'][1]['runnable']);
|
||||
}
|
||||
|
||||
public function testCollectQueryWithNoTypes()
|
||||
@ -134,7 +148,7 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
/**
|
||||
* @dataProvider paramProvider
|
||||
*/
|
||||
public function testSerialization($param, $types, $expected, $explainable)
|
||||
public function testSerialization($param, $types, $expected, $explainable, bool $runnable = true)
|
||||
{
|
||||
$queries = [
|
||||
['sql' => 'SELECT * FROM table1 WHERE field1 = ?1', 'params' => [$param], 'types' => $types, 'executionMS' => 1],
|
||||
@ -144,8 +158,19 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
$c = unserialize(serialize($c));
|
||||
|
||||
$collectedQueries = $c->getQueries();
|
||||
$this->assertEquals($expected, $collectedQueries['default'][0]['params'][0]);
|
||||
|
||||
$collectedParam = $collectedQueries['default'][0]['params'][0];
|
||||
if ($collectedParam instanceof Data) {
|
||||
$dumper = new CliDumper($out = fopen('php://memory', 'r+b'));
|
||||
$dumper->setColors(false);
|
||||
$collectedParam->dump($dumper);
|
||||
$this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true));
|
||||
} else {
|
||||
$this->assertEquals($expected, $collectedParam);
|
||||
}
|
||||
|
||||
$this->assertEquals($explainable, $collectedQueries['default'][0]['explainable']);
|
||||
$this->assertSame($runnable, $collectedQueries['default'][0]['runnable']);
|
||||
}
|
||||
|
||||
public function paramProvider()
|
||||
@ -156,19 +181,46 @@ class DoctrineDataCollectorTest extends TestCase
|
||||
[true, [], true, true],
|
||||
[null, [], null, true],
|
||||
[new \DateTime('2011-09-11'), ['date'], '2011-09-11', true],
|
||||
[fopen(__FILE__, 'r'), [], '/* Resource(stream) */', false],
|
||||
[new \stdClass(), [], '/* Object(stdClass) */', false],
|
||||
[fopen(__FILE__, 'r'), [], '/* Resource(stream) */', false, false],
|
||||
[
|
||||
new \stdClass(),
|
||||
[],
|
||||
<<<EOTXT
|
||||
{#%d
|
||||
⚠: "Object of class "stdClass" could not be converted to string."
|
||||
}
|
||||
EOTXT
|
||||
,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
new StringRepresentableClass(),
|
||||
[],
|
||||
'/* Object(Symfony\Bridge\Doctrine\Tests\DataCollector\StringRepresentableClass): */"string representation"',
|
||||
<<<EOTXT
|
||||
Symfony\Bridge\Doctrine\Tests\DataCollector\StringRepresentableClass {#%d
|
||||
__toString(): "string representation"
|
||||
}
|
||||
EOTXT
|
||||
,
|
||||
false,
|
||||
],
|
||||
];
|
||||
|
||||
if (version_compare(Version::VERSION, '2.6', '>=')) {
|
||||
$tests[] = ['this is not a date', ['date'], 'this is not a date', false];
|
||||
$tests[] = [new \stdClass(), ['date'], '/* Object(stdClass) */', false];
|
||||
$tests[] = ['this is not a date', ['date'], "⚠ Could not convert PHP value 'this is not a date' of type 'string' to type 'date'. Expected one of the following types: null, DateTime", false, false];
|
||||
$tests[] = [
|
||||
new \stdClass(),
|
||||
['date'],
|
||||
<<<EOTXT
|
||||
{#%d
|
||||
⚠: "Could not convert PHP value of type 'stdClass' to type 'date'. Expected one of the following types: null, DateTime"
|
||||
}
|
||||
EOTXT
|
||||
,
|
||||
false,
|
||||
false,
|
||||
];
|
||||
}
|
||||
|
||||
return $tests;
|
||||
|
@ -38,10 +38,11 @@ CHANGELOG
|
||||
* Overriding the methods `KernelTestCase::tearDown()` and `WebTestCase::tearDown()` without the `void` return-type is deprecated.
|
||||
* Added new `error_controller` configuration to handle system exceptions
|
||||
* Added sort option for `translation:update` command.
|
||||
* [BC Break] The `framework.messenger.routing.senders` config key is not deep merged anymore.
|
||||
* [BC Break] The `framework.messenger.routing.senders` config key is not deeply merged anymore.
|
||||
* Added `secrets:*` commands and `%env(secret:...)%` processor to deal with secrets seamlessly.
|
||||
* Made `framework.session.handler_id` accept a DSN
|
||||
* Marked the `RouterDataCollector` class as `@final`.
|
||||
* [BC Break] The `framework.messenger.buses.<name>.middleware` config key is not deeply merged anymore.
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
@ -1156,6 +1156,7 @@ class Configuration implements ConfigurationInterface
|
||||
->defaultTrue()
|
||||
->end()
|
||||
->arrayNode('middleware')
|
||||
->performNoDeepMerging()
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return \is_string($v) || (\is_array($v) && !\is_int(key($v))); })
|
||||
->then(function ($v) { return [$v]; })
|
||||
|
@ -1115,11 +1115,18 @@ class FrameworkExtension extends Extension
|
||||
$files[$locale][] = (string) $file;
|
||||
}
|
||||
|
||||
$projectDir = $container->getParameter('kernel.project_dir');
|
||||
|
||||
$options = array_merge(
|
||||
$translator->getArgument(4),
|
||||
[
|
||||
'resource_files' => $files,
|
||||
'scanned_directories' => array_merge($dirs, $nonExistingDirs),
|
||||
'scanned_directories' => $scannedDirectories = array_merge($dirs, $nonExistingDirs),
|
||||
'cache_vary' => [
|
||||
'scanned_directories' => array_map(static function (string $dir) use ($projectDir): string {
|
||||
return 0 === strpos($dir, $projectDir.'/') ? substr($dir, 1 + \strlen($projectDir)) : $dir;
|
||||
}, $scannedDirectories),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -256,6 +256,64 @@ class ConfigurationTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function testBusMiddlewareDontMerge()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(true);
|
||||
$config = $processor->processConfiguration($configuration, [
|
||||
[
|
||||
'messenger' => [
|
||||
'default_bus' => 'existing_bus',
|
||||
'buses' => [
|
||||
'existing_bus' => [
|
||||
'middleware' => 'existing_bus.middleware',
|
||||
],
|
||||
'common_bus' => [
|
||||
'default_middleware' => false,
|
||||
'middleware' => 'common_bus.old_middleware',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'messenger' => [
|
||||
'buses' => [
|
||||
'common_bus' => [
|
||||
'middleware' => 'common_bus.new_middleware',
|
||||
],
|
||||
'new_bus' => [
|
||||
'middleware' => 'new_bus.middleware',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'existing_bus' => [
|
||||
'default_middleware' => true,
|
||||
'middleware' => [
|
||||
['id' => 'existing_bus.middleware', 'arguments' => []],
|
||||
],
|
||||
],
|
||||
'common_bus' => [
|
||||
'default_middleware' => false,
|
||||
'middleware' => [
|
||||
['id' => 'common_bus.new_middleware', 'arguments' => []],
|
||||
],
|
||||
],
|
||||
'new_bus' => [
|
||||
'default_middleware' => true,
|
||||
'middleware' => [
|
||||
['id' => 'new_bus.middleware', 'arguments' => []],
|
||||
],
|
||||
],
|
||||
],
|
||||
$config['messenger']['buses']
|
||||
);
|
||||
}
|
||||
|
||||
protected static function getBundleDefaultConfig()
|
||||
{
|
||||
return [
|
||||
|
@ -738,6 +738,8 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
);
|
||||
|
||||
$this->assertNotEmpty($nonExistingDirectories, 'FrameworkBundle should pass non existing directories to Translator');
|
||||
|
||||
$this->assertSame('Fixtures/translations', $options['cache_vary']['scanned_directories'][3]);
|
||||
}
|
||||
|
||||
public function testTranslatorMultipleFallbacks()
|
||||
|
@ -217,8 +217,10 @@ class TranslatorTest extends TestCase
|
||||
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
|
||||
],
|
||||
],
|
||||
'cache_vary' => [
|
||||
'scanned_directories' => [
|
||||
__DIR__.'/../Fixtures/Resources/translations/',
|
||||
'/Fixtures/Resources/translations/',
|
||||
],
|
||||
],
|
||||
], 'yml');
|
||||
|
||||
@ -233,9 +235,11 @@ class TranslatorTest extends TestCase
|
||||
__DIR__.'/../Fixtures/Resources/translations2/ccc.fr.yml',
|
||||
],
|
||||
],
|
||||
'cache_vary' => [
|
||||
'scanned_directories' => [
|
||||
__DIR__.'/../Fixtures/Resources/translations/',
|
||||
__DIR__.'/../Fixtures/Resources/translations2/',
|
||||
'/Fixtures/Resources/translations/',
|
||||
'/Fixtures/Resources/translations2/',
|
||||
],
|
||||
],
|
||||
], 'yml');
|
||||
|
||||
|
@ -34,6 +34,7 @@ class Translator extends BaseTranslator implements WarmableInterface
|
||||
'debug' => false,
|
||||
'resource_files' => [],
|
||||
'scanned_directories' => [],
|
||||
'cache_vary' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
@ -64,6 +65,7 @@ class Translator extends BaseTranslator implements WarmableInterface
|
||||
* * cache_dir: The cache directory (or null to disable caching)
|
||||
* * debug: Whether to enable debugging or not (false by default)
|
||||
* * resource_files: List of translation resources available grouped by locale.
|
||||
* * cache_vary: An array of data that is serialized to generate the cached catalogue name.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
@ -82,9 +84,7 @@ class Translator extends BaseTranslator implements WarmableInterface
|
||||
$this->resourceFiles = $this->options['resource_files'];
|
||||
$this->scannedDirectories = $this->options['scanned_directories'];
|
||||
|
||||
parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug'], [
|
||||
'scanned_directories' => $this->scannedDirectories,
|
||||
]);
|
||||
parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug'], $this->options['cache_vary']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,6 +184,8 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
$delete = $this->getConnection()->prepare($deleteSql);
|
||||
} catch (TableNotFoundException $e) {
|
||||
return true;
|
||||
} catch (\PDOException $e) {
|
||||
return true;
|
||||
}
|
||||
$delete->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
|
||||
@ -194,6 +196,8 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
return $delete->execute();
|
||||
} catch (TableNotFoundException $e) {
|
||||
return true;
|
||||
} catch (\PDOException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,6 +273,7 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
try {
|
||||
$conn->exec($sql);
|
||||
} catch (TableNotFoundException $e) {
|
||||
} catch (\PDOException $e) {
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -285,6 +290,7 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
$stmt = $this->getConnection()->prepare($sql);
|
||||
$stmt->execute(array_values($ids));
|
||||
} catch (TableNotFoundException $e) {
|
||||
} catch (\PDOException $e) {
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -341,6 +347,11 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
$this->createTable();
|
||||
}
|
||||
$stmt = $conn->prepare($sql);
|
||||
} catch (\PDOException $e) {
|
||||
if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
|
||||
$this->createTable();
|
||||
}
|
||||
$stmt = $conn->prepare($sql);
|
||||
}
|
||||
|
||||
if ('sqlsrv' === $driver || 'oci' === $driver) {
|
||||
@ -375,6 +386,11 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
|
||||
$this->createTable();
|
||||
}
|
||||
$stmt->execute();
|
||||
} catch (\PDOException $e) {
|
||||
if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
|
||||
$this->createTable();
|
||||
}
|
||||
$stmt->execute();
|
||||
}
|
||||
if (null === $driver && !$stmt->rowCount()) {
|
||||
try {
|
||||
|
0
src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php
Executable file → Normal file
0
src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php
Executable file → Normal file
@ -89,7 +89,7 @@ class RedirectResponse extends Response
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="refresh" content="0;url=%1$s" />
|
||||
<meta http-equiv="refresh" content="0;url=\'%1$s\'" />
|
||||
|
||||
<title>Redirecting to %1$s</title>
|
||||
</head>
|
||||
|
@ -30,9 +30,15 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* @var int Time to live in seconds
|
||||
*/
|
||||
private $ttl;
|
||||
|
||||
/**
|
||||
* List of available options:
|
||||
* * prefix: The prefix to use for the keys in order to avoid collision on the Redis server.
|
||||
* * prefix: The prefix to use for the keys in order to avoid collision on the Redis server
|
||||
* * ttl: The time to live in seconds.
|
||||
*
|
||||
* @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis
|
||||
*
|
||||
@ -51,12 +57,13 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
throw new \InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, %s given', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis)));
|
||||
}
|
||||
|
||||
if ($diff = array_diff(array_keys($options), ['prefix'])) {
|
||||
if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The following options are not supported "%s"', implode(', ', $diff)));
|
||||
}
|
||||
|
||||
$this->redis = $redis;
|
||||
$this->prefix = $options['prefix'] ?? 'sf_s';
|
||||
$this->ttl = $options['ttl'] ?? (int) ini_get('session.gc_maxlifetime');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +79,7 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
protected function doWrite(string $sessionId, string $data): bool
|
||||
{
|
||||
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime'), $data);
|
||||
$result = $this->redis->setEx($this->prefix.$sessionId, $this->ttl, $data);
|
||||
|
||||
return $result && !$result instanceof ErrorInterface;
|
||||
}
|
||||
@ -108,6 +115,6 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
public function updateTimestamp($sessionId, $data)
|
||||
{
|
||||
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime'));
|
||||
return (bool) $this->redis->expire($this->prefix.$sessionId, $this->ttl);
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,7 @@ class RedirectResponseTest extends TestCase
|
||||
{
|
||||
$response = new RedirectResponse('foo.bar');
|
||||
|
||||
$this->assertEquals(1, preg_match(
|
||||
'#<meta http-equiv="refresh" content="\d+;url=foo\.bar" />#',
|
||||
preg_replace(['/\s+/', '/\'/'], [' ', '"'], $response->getContent())
|
||||
));
|
||||
$this->assertRegExp('#<meta http-equiv="refresh" content="\d+;url=\'foo\.bar\'" />#', preg_replace('/\s+/', ' ', $response->getContent()));
|
||||
}
|
||||
|
||||
public function testRedirectResponseConstructorEmptyUrl()
|
||||
|
@ -139,7 +139,37 @@ abstract class AbstractRedisSessionHandlerTestCase extends TestCase
|
||||
{
|
||||
return [
|
||||
[['prefix' => 'session'], true],
|
||||
[['ttl' => 1000], true],
|
||||
[['prefix' => 'sfs', 'ttl' => 1000], true],
|
||||
[['prefix' => 'sfs', 'foo' => 'bar'], false],
|
||||
[['ttl' => 'sfs', 'foo' => 'bar'], false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTtlFixtures
|
||||
*/
|
||||
public function testUseTtlOption(int $ttl)
|
||||
{
|
||||
$options = [
|
||||
'prefix' => self::PREFIX,
|
||||
'ttl' => $ttl,
|
||||
];
|
||||
|
||||
$handler = new RedisSessionHandler($this->redisClient, $options);
|
||||
$handler->write('id', 'data');
|
||||
$redisTtl = $this->redisClient->ttl(self::PREFIX.'id');
|
||||
|
||||
$this->assertLessThan($redisTtl, $ttl - 5);
|
||||
$this->assertGreaterThan($redisTtl, $ttl + 5);
|
||||
}
|
||||
|
||||
public function getTtlFixtures(): array
|
||||
{
|
||||
return [
|
||||
['ttl' => 5000],
|
||||
['ttl' => 120],
|
||||
['ttl' => 60],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user