From c79bd63c934ac7bc45bc3590f93c06b04f4ea0e8 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 7 Jun 2023 11:34:23 +0200 Subject: [PATCH] Introduce TracingDriverForV3Point2 This driver does not implement the deprecated `VersionAwarePlatformDriver`. It's automatically picked when `doctrine/dbal` version `3.2.0` or higher is installed. Fixes #579 --- .github/workflows/tests.yaml | 12 ++ phpstan-baseline.neon | 2 +- psalm-baseline.xml | 11 ++ .../DBAL/TracingDriverForV3Point2.php | 89 ++++++++++++++ src/aliases.php | 10 +- tests/DoctrineTestCase.php | 12 +- .../DBAL/TracingDriverForV3Point2Test.php | 112 ++++++++++++++++++ .../Doctrine/DBAL/TracingDriverForV3Test.php | 4 + .../DBAL/TracingStatementForV3Test.php | 3 + 9 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 src/Tracing/Doctrine/DBAL/TracingDriverForV3Point2.php create mode 100644 tests/Tracing/Doctrine/DBAL/TracingDriverForV3Point2Test.php diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 16c124ff..4ca224fb 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -30,6 +30,8 @@ jobs: - 6.* dependencies: - highest + doctrine-dbal: + - highest exclude: - php: '7.2' symfony-version: 6.* @@ -41,12 +43,18 @@ jobs: - php: '7.2' symfony-version: 4.4.* dependencies: lowest + doctrine-dbal: '^2.13' - php: '7.2' symfony-version: 5.* dependencies: lowest + doctrine-dbal: '^2.13' - php: '8.0' symfony-version: 6.* dependencies: lowest + doctrine-dbal: '^2.13' + - php: '8.0' + symfony-version: 6.* + doctrine-dbal: '<3.2' steps: - name: Checkout @@ -68,6 +76,10 @@ jobs: run: composer require --dev phpunit/phpunit ^9.3.9 --no-update if: matrix.php == '8.0' && matrix.dependencies == 'lowest' + - name: Update Doctrine DBAL + run: composer require --dev doctrine/dbal "${{ matrix.doctrine-dbal }}" --no-update + if: matrix.doctrine-dbal != 'highest' + - name: Install dependencies uses: ramsey/composer-install@v1 with: diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ee3ce335..2b4858f5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -231,7 +231,7 @@ parameters: path: src/Tracing/Doctrine/DBAL/TracingServerInfoAwareDriverConnection.php - - message: "#^Parameter \\#2 \\$callback of method Sentry\\\\SentryBundle\\\\Tracing\\\\Doctrine\\\\DBAL\\\\AbstractTracingStatement\\:\\:traceFunction\\(\\) expects callable\\(\\.\\.\\.mixed\\)\\: Doctrine\\\\DBAL\\\\Driver\\\\Result, array\\{Doctrine\\\\DBAL\\\\Driver\\\\Statement, 'execute'\\} given\\.$#" + message: "#^Parameter \\#2 \\$callback of method Sentry\\\\SentryBundle\\\\Tracing\\\\Doctrine\\\\DBAL\\\\AbstractTracingStatement\\:\\:traceFunction\\(\\) expects callable\\(mixed \\.\\.\\.\\)\\: Doctrine\\\\DBAL\\\\Driver\\\\Result, array\\{Doctrine\\\\DBAL\\\\Driver\\\\Statement, 'execute'\\} given\\.$#" count: 1 path: src/Tracing/Doctrine/DBAL/TracingStatementForV3.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 32016223..ab59d0e4 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -50,6 +50,17 @@ $params + + + $this->decoratedDriver->getSchemaManager($conn, $platform) + + + AbstractSchemaManager<T> + + + $params + + toStream diff --git a/src/Tracing/Doctrine/DBAL/TracingDriverForV3Point2.php b/src/Tracing/Doctrine/DBAL/TracingDriverForV3Point2.php new file mode 100644 index 00000000..0cb3bf60 --- /dev/null +++ b/src/Tracing/Doctrine/DBAL/TracingDriverForV3Point2.php @@ -0,0 +1,89 @@ += 3.2. + * + * @internal + * + * @phpstan-import-type Params from \Doctrine\DBAL\DriverManager as ConnectionParams + */ +final class TracingDriverForV3Point2 implements Driver +{ + /** + * @var TracingDriverConnectionFactoryInterface The connection factory + */ + private $connectionFactory; + + /** + * @var Driver The instance of the decorated driver + */ + private $decoratedDriver; + + /** + * Constructor. + * + * @param TracingDriverConnectionFactoryInterface $connectionFactory The connection factory + * @param Driver $decoratedDriver The instance of the driver to decorate + */ + public function __construct(TracingDriverConnectionFactoryInterface $connectionFactory, Driver $decoratedDriver) + { + $this->connectionFactory = $connectionFactory; + $this->decoratedDriver = $decoratedDriver; + } + + /** + * {@inheritdoc} + * + * @phpstan-param ConnectionParams $params + */ + public function connect(array $params): TracingDriverConnectionInterface + { + return $this->connectionFactory->create( + $this->decoratedDriver->connect($params), + $this->decoratedDriver->getDatabasePlatform(), + $params + ); + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform(): AbstractPlatform + { + return $this->decoratedDriver->getDatabasePlatform(); + } + + /** + * {@inheritdoc} + * + * @phpstan-template T of AbstractPlatform + * + * @phpstan-param T $platform + * + * @phpstan-return AbstractSchemaManager + */ + public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager + { + return $this->decoratedDriver->getSchemaManager($conn, $platform); + } + + /** + * {@inheritdoc} + */ + public function getExceptionConverter(): ExceptionConverter + { + return $this->decoratedDriver->getExceptionConverter(); + } +} diff --git a/src/aliases.php b/src/aliases.php index 839a55c9..5142f7d1 100644 --- a/src/aliases.php +++ b/src/aliases.php @@ -4,6 +4,8 @@ namespace Sentry\SentryBundle; +use Composer\InstalledVersions; +use Doctrine\DBAL\Exception\SchemaDoesNotExist; use Doctrine\DBAL\Result; use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapter; use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapterForV2; @@ -14,6 +16,7 @@ use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriver; use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverForV2; use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverForV3; +use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverForV3Point2; use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatement; use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatementForV2; use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatementForV3; @@ -53,7 +56,12 @@ class_alias(TraceableTagAwareCacheAdapterForV2::class, TraceableTagAwareCacheAda if (!class_exists(TracingStatement::class)) { if (class_exists(Result::class)) { class_alias(TracingStatementForV3::class, TracingStatement::class); - class_alias(TracingDriverForV3::class, TracingDriver::class); + + if (class_exists(SchemaDoesNotExist::class)) { + class_alias(TracingDriverForV3Point2::class, TracingDriver::class); + } else { + class_alias(TracingDriverForV3::class, TracingDriver::class); + } } elseif (interface_exists(Result::class)) { class_alias(TracingStatementForV2::class, TracingStatement::class); class_alias(TracingDriverForV2::class, TracingDriver::class); diff --git a/tests/DoctrineTestCase.php b/tests/DoctrineTestCase.php index 6d4c7626..1c84210a 100644 --- a/tests/DoctrineTestCase.php +++ b/tests/DoctrineTestCase.php @@ -4,9 +4,12 @@ namespace Sentry\SentryBundle\Tests; +use Composer\InstalledVersions; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Event\TransactionBeginEventArgs; +use Doctrine\DBAL\Exception\SchemaDoesNotExist; use PHPUnit\Framework\TestCase; abstract class DoctrineTestCase extends TestCase @@ -25,7 +28,14 @@ protected static function isDoctrineDBALVersion2Installed(): bool protected static function isDoctrineDBALVersion3Installed(): bool { return self::isDoctrineDBALInstalled() - && !self::isDoctrineDBALVersion2Installed(); + && !self::isDoctrineDBALVersion2Installed() + && !self::isDoctrineDBALVersion3Point2Installed(); + } + + protected static function isDoctrineDBALVersion3Point2Installed(): bool + { + return self::isDoctrineDBALInstalled() + && class_exists(SchemaDoesNotExist::class); } protected static function isDoctrineBundlePackageInstalled(): bool diff --git a/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Point2Test.php b/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Point2Test.php new file mode 100644 index 00000000..8f335f2e --- /dev/null +++ b/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Point2Test.php @@ -0,0 +1,112 @@ += 3.2.'); + } + } + + protected function setUp(): void + { + $this->connectionFactory = $this->createMock(TracingDriverConnectionFactoryInterface::class); + } + + public function testConnect(): void + { + $params = ['host' => 'localhost']; + $databasePlatform = $this->createMock(AbstractPlatform::class); + $driverConnection = $this->createMock(DriverConnectionInterface::class); + $tracingDriverConnection = $this->createMock(TracingDriverConnectionInterface::class); + $decoratedDriver = $this->createMock(DriverInterface::class); + + $decoratedDriver->expects($this->once()) + ->method('connect') + ->with($params) + ->willReturn($driverConnection); + + $decoratedDriver->expects($this->once()) + ->method('getDatabasePlatform') + ->willReturn($databasePlatform); + + $this->connectionFactory->expects($this->once()) + ->method('create') + ->with($driverConnection, $databasePlatform, $params) + ->willReturn($tracingDriverConnection); + + $driver = new TracingDriverForV3Point2($this->connectionFactory, $decoratedDriver); + + $this->assertSame($tracingDriverConnection, $driver->connect($params)); + } + + public function testGetDatabasePlatform(): void + { + $databasePlatform = $this->createMock(AbstractPlatform::class); + + $decoratedDriver = $this->createMock(DriverInterface::class); + $decoratedDriver->expects($this->once()) + ->method('getDatabasePlatform') + ->willReturn($databasePlatform); + + $driver = new TracingDriverForV3Point2($this->connectionFactory, $decoratedDriver); + + $this->assertSame($databasePlatform, $driver->getDatabasePlatform()); + } + + /** + * @group legacy + */ + public function testGetSchemaManager(): void + { + $connection = $this->createMock(Connection::class); + $databasePlatform = $this->createMock(AbstractPlatform::class); + $schemaManager = $this->createMock(AbstractSchemaManager::class); + + $decoratedDriver = $this->createMock(DriverInterface::class); + $decoratedDriver->expects($this->once()) + ->method('getSchemaManager') + ->with($connection, $databasePlatform) + ->willReturn($schemaManager); + + $driver = new TracingDriverForV3Point2($this->connectionFactory, $decoratedDriver); + + $this->assertSame($schemaManager, $driver->getSchemaManager($connection, $databasePlatform)); + } + + public function testGetExceptionConverter(): void + { + $exceptionConverter = $this->createMock(ExceptionConverter::class); + + $decoratedDriver = $this->createMock(DriverInterface::class); + $decoratedDriver->expects($this->once()) + ->method('getExceptionConverter') + ->willReturn($exceptionConverter); + + $driver = new TracingDriverForV3Point2($this->connectionFactory, $decoratedDriver); + + $this->assertSame($exceptionConverter, $driver->getExceptionConverter()); + } +} diff --git a/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Test.php b/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Test.php index af3a857b..97eec5dc 100644 --- a/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Test.php +++ b/tests/Tracing/Doctrine/DBAL/TracingDriverForV3Test.php @@ -29,6 +29,10 @@ public static function setUpBeforeClass(): void if (!self::isDoctrineDBALVersion3Installed()) { self::markTestSkipped('This test requires the version of the "doctrine/dbal" Composer package to be >= 3.0.'); } + + if (self::isDoctrineDBALVersion3Point2Installed()) { + self::markTestSkipped('This test requires the version of the "doctrine/dbal" Composer package to be >= 3.0 <= 3.2.'); + } } protected function setUp(): void diff --git a/tests/Tracing/Doctrine/DBAL/TracingStatementForV3Test.php b/tests/Tracing/Doctrine/DBAL/TracingStatementForV3Test.php index 566b178a..653b7d87 100644 --- a/tests/Tracing/Doctrine/DBAL/TracingStatementForV3Test.php +++ b/tests/Tracing/Doctrine/DBAL/TracingStatementForV3Test.php @@ -55,6 +55,9 @@ public function testBindValue(): void $this->assertTrue($this->statement->bindValue('foo', 'bar', ParameterType::INTEGER)); } + /** + * @group legacy + */ public function testBindParam(): void { $variable = 'bar';