From 3cf105766aab84c6e09b92cdd2a14a103a081233 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 14 Jul 2021 15:30:39 +0200 Subject: [PATCH 1/3] [VarDumper] Support for intersection types Signed-off-by: Alexander M. Turek --- .github/patch-types.php | 1 + .../VarDumper/Caster/ReflectionCaster.php | 2 +- .../Tests/Caster/ReflectionCasterTest.php | 51 ++++++++++++++++++- .../ReflectionIntersectionTypeFixture.php | 8 +++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php diff --git a/.github/patch-types.php b/.github/patch-types.php index 95e56b5984..e139c2c73e 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -41,6 +41,7 @@ foreach ($loader->getClassMap() as $class => $file) { case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php'): case false !== strpos($file, '/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ObjectOuter.php'): case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/NotLoadableClass.php'): + case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php'): continue 2; } diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 95c1dbf6ff..4a1ae4f6b7 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -102,7 +102,7 @@ class ReflectionCaster $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; - } elseif ($c instanceof \ReflectionUnionType) { + } elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) { $a[$prefix.'allowsNull'] = $c->allowsNull(); self::addMap($a, $c, [ 'types' => 'getTypes', diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index f9a8bd9440..e4a8974ff1 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -17,6 +17,7 @@ use Symfony\Component\VarDumper\Test\VarDumperTestTrait; use Symfony\Component\VarDumper\Tests\Fixtures\ExtendsReflectionTypeFixture; use Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo; use Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass; +use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionIntersectionTypeFixture; use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionNamedTypeFixture; use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionUnionTypeFixture; @@ -78,7 +79,7 @@ Closure($x) { $b: & 123 } file: "%sReflectionCasterTest.php" - line: "71 to 71" + line: "72 to 72" } EOTXT , $var @@ -228,6 +229,26 @@ EOTXT ); } + /** + * @requires PHP 8.1 + */ + public function testReflectionParameterIntersection() + { + $f = eval('return function (Traversable&Countable $a) {};'); + $var = new \ReflectionParameter($f, 0); + + $this->assertDumpMatchesFormat( + <<<'EOTXT' +ReflectionParameter { + +name: "a" + position: 0 + typeHint: "Traversable&Countable" +} +EOTXT + , $var + ); + } + /** * @requires PHP 7.4 */ @@ -292,6 +313,34 @@ EOTXT ); } + /** + * @requires PHP 8.1 + */ + public function testReflectionIntersectionType() + { + $var = (new \ReflectionProperty(ReflectionIntersectionTypeFixture::class, 'a'))->getType(); + $this->assertDumpMatchesFormat( + <<<'EOTXT' +ReflectionIntersectionType { + allowsNull: false + types: array:2 [ + 0 => ReflectionNamedType { + name: "Traversable" + allowsNull: false + isBuiltin: false + } + 1 => ReflectionNamedType { + name: "Countable" + allowsNull: false + isBuiltin: false + } + ] +} +EOTXT + , $var + ); + } + /** * @requires PHP 8 */ diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php new file mode 100644 index 0000000000..d9d8d21769 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php @@ -0,0 +1,8 @@ + Date: Wed, 7 Jul 2021 14:24:36 +0200 Subject: [PATCH 2/3] [Cache] Support decorated Dbal drivers in PdoAdapter --- .github/patch-types.php | 1 + .../Tests/Adapter/PdoDbalAdapterTest.php | 28 +++++++++++ .../Cache/Tests/Fixtures/DriverWrapper.php | 48 +++++++++++++++++++ .../Component/Cache/Traits/PdoTrait.php | 9 ++++ 4 files changed, 86 insertions(+) create mode 100644 src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php diff --git a/.github/patch-types.php b/.github/patch-types.php index 95e56b5984..be1c9f2746 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -25,6 +25,7 @@ foreach ($loader->getClassMap() as $class => $file) { case false !== strpos($file = realpath($file), '/vendor/'): case false !== strpos($file, '/src/Symfony/Bridge/PhpUnit/'): case false !== strpos($file, '/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Article.php'): + case false !== strpos($file, '/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php'): case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php'): case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/BadParent.php'): case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/ParseError.php'): diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php index c31f96dda5..3bfa3070b5 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php @@ -11,10 +11,13 @@ namespace Symfony\Component\Cache\Tests\Adapter; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Driver\Middleware; use Doctrine\DBAL\DriverManager; use PHPUnit\Framework\SkippedTestSuiteError; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\PdoAdapter; +use Symfony\Component\Cache\Tests\Fixtures\DriverWrapper; /** * @group time-sensitive @@ -43,4 +46,29 @@ class PdoDbalAdapterTest extends AdapterTestCase { return new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime); } + + public function testConfigureSchemaDecoratedDbalDriver() + { + $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]); + if (!interface_exists(Middleware::class)) { + $this->markTestSkipped('doctrine/dbal v2 does not support custom drivers using middleware'); + } + + $middleware = $this->createMock(Middleware::class); + $middleware + ->method('wrap') + ->willReturn(new DriverWrapper($connection->getDriver())); + + $config = new Configuration(); + $config->setMiddlewares([$middleware]); + + $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile], $config); + + $adapter = new PdoAdapter($connection); + $adapter->createTable(); + + $item = $adapter->getItem('key'); + $item->set('value'); + $this->assertTrue($adapter->save($item)); + } } diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php new file mode 100644 index 0000000000..bb73d8d0cf --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Fixtures; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Schema\AbstractSchemaManager; + +class DriverWrapper implements Driver +{ + /** @var Driver */ + private $driver; + + public function __construct(Driver $driver) + { + $this->driver = $driver; + } + + public function connect(array $params, $username = null, $password = null, array $driverOptions = []): Driver\Connection + { + return $this->driver->connect($params, $username, $password, $driverOptions); + } + + public function getDatabasePlatform(): AbstractPlatform + { + return $this->driver->getDatabasePlatform(); + } + + public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager + { + return $this->driver->getSchemaManager($conn, $platform); + } + + public function getExceptionConverter(): Driver\API\ExceptionConverter + { + return $this->driver->getExceptionConverter(); + } +} diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index e115acfb89..a2129c459b 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -448,6 +448,15 @@ trait PdoTrait case $driver instanceof \Doctrine\DBAL\Driver\PDO\SQLSrv\Driver: $this->driver = 'sqlsrv'; break; + case $driver instanceof \Doctrine\DBAL\Driver: + $this->driver = [ + 'mssql' => 'sqlsrv', + 'oracle' => 'oci', + 'postgresql' => 'pgsql', + 'sqlite' => 'sqlite', + 'mysql' => 'mysql', + ][$driver->getDatabasePlatform()->getName()] ?? \get_class($driver); + break; default: $this->driver = \get_class($driver); break; From 1261a4139d629f65846afb06291c478c17d222cd Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 15 Jul 2021 01:45:22 +0200 Subject: [PATCH 3/3] [HttpFoundation] Fix return types of SessionHandler::gc() Signed-off-by: Alexander M. Turek --- .../Session/Storage/Handler/MemcachedSessionHandler.php | 5 +++-- .../Session/Storage/Handler/MigratingSessionHandler.php | 2 +- .../Session/Storage/Handler/MongoDbSessionHandler.php | 9 ++++----- .../Session/Storage/Handler/NullSessionHandler.php | 4 ++-- .../Session/Storage/Handler/PdoSessionHandler.php | 4 ++-- .../Session/Storage/Handler/RedisSessionHandler.php | 7 +++++-- .../Handler/AbstractRedisSessionHandlerTestCase.php | 2 +- .../Tests/Session/Storage/Handler/Fixtures/common.inc | 5 +++-- .../Storage/Handler/MemcachedSessionHandlerTest.php | 2 +- .../Storage/Handler/MongoDbSessionHandlerTest.php | 7 ++++++- 10 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php index c8f1189909..d8663a57b7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -99,12 +99,13 @@ class MemcachedSessionHandler extends AbstractSessionHandler } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { // not required here because memcached will auto expire the records anyhow. - return true; + return 0; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php index c3e7ef6e60..a4f28ef21b 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php @@ -63,7 +63,7 @@ class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdat } /** - * @return bool + * @return int|false */ #[\ReturnTypeWillChange] public function gc($maxlifetime) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php index 6cb8847786..772a3e56bb 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -100,15 +100,14 @@ class MongoDbSessionHandler extends AbstractSessionHandler } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { - $this->getCollection()->deleteMany([ + return $this->getCollection()->deleteMany([ $this->options['expiry_field'] => ['$lt' => new \MongoDB\BSON\UTCDateTime()], - ]); - - return true; + ])->getDeletedCount(); } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php index c34c25edbb..a85ab65869 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php @@ -70,11 +70,11 @@ class NullSessionHandler extends AbstractSessionHandler } /** - * @return bool + * @return int|false */ #[\ReturnTypeWillChange] public function gc($maxlifetime) { - return true; + return 0; } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index d3c5651d41..5fec9b17ec 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -290,7 +290,7 @@ class PdoSessionHandler extends AbstractSessionHandler } /** - * @return bool + * @return int|false */ #[\ReturnTypeWillChange] public function gc($maxlifetime) @@ -299,7 +299,7 @@ class PdoSessionHandler extends AbstractSessionHandler // This way, pruning expired sessions does not block them from being started while the current session is used. $this->gcCalled = true; - return true; + return 0; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php index 699d6da6f6..a9c4e392e9 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php @@ -104,10 +104,13 @@ class RedisSessionHandler extends AbstractSessionHandler /** * {@inheritdoc} + * + * @return int|false */ - public function gc($maxlifetime): bool + #[\ReturnTypeWillChange] + public function gc($maxlifetime) { - return true; + return 0; } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php index de5188d42c..3dcb3c51db 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php @@ -114,7 +114,7 @@ abstract class AbstractRedisSessionHandlerTestCase extends TestCase public function testGcSession() { - $this->assertTrue($this->storage->gc(123)); + $this->assertIsInt($this->storage->gc(123)); } public function testUpdateTimestamp() diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc index a887f607e8..fd662e3a16 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/Fixtures/common.inc @@ -121,11 +121,12 @@ class TestSessionHandler extends AbstractSessionHandler return true; } - public function gc($maxLifetime): bool + #[\ReturnTypeWillChange] + public function gc($maxLifetime) { echo __FUNCTION__, "\n"; - return true; + return 1; } protected function doRead($sessionId): string diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php index 200567a29d..d404b74c6a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php @@ -113,7 +113,7 @@ class MemcachedSessionHandlerTest extends TestCase public function testGcSession() { - $this->assertTrue($this->storage->gc(123)); + $this->assertIsInt($this->storage->gc(123)); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php index 01b92dfa22..bf8021c155 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php @@ -184,9 +184,14 @@ class MongoDbSessionHandlerTest extends TestCase ->willReturnCallback(function ($criteria) { $this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $criteria[$this->options['expiry_field']]['$lt']); $this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000)); + + $result = $this->createMock(\MongoDB\DeleteResult::class); + $result->method('getDeletedCount')->willReturn(42); + + return $result; }); - $this->assertTrue($this->storage->gc(1)); + $this->assertSame(42, $this->storage->gc(1)); } public function testGetConnection()