Skip to content

Introduce TracingDriverForV32 for DBAL >= 3.2 #723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
- 6.*
dependencies:
- highest
doctrine-dbal:
- highest
exclude:
- php: '7.2'
symfony-version: 6.*
Expand All @@ -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
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"require-dev": {
"doctrine/dbal": "^2.13||^3.0",
"doctrine/doctrine-bundle": "^1.12||^2.5",
"friendsofphp/php-cs-fixer": "^2.19||^3.6",
"friendsofphp/php-cs-fixer": "^2.19||<=3.16.0",
"jangregor/phpstan-prophecy": "^1.0",
"monolog/monolog": "^1.3||^2.0",
"phpspec/prophecy": "!=1.11.0",
Expand Down
2 changes: 1 addition & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 11 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
<code>$params</code>
</MoreSpecificImplementedParamType>
</file>
<file src="src/Tracing/Doctrine/DBAL/TracingDriverForV32.php">
<InvalidReturnStatement occurrences="1">
<code>$this-&gt;decoratedDriver-&gt;getSchemaManager($conn, $platform)</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>AbstractSchemaManager&lt;T&gt;</code>
</InvalidReturnType>
<MoreSpecificImplementedParamType occurrences="1">
<code>$params</code>
</MoreSpecificImplementedParamType>
</file>
<file src="src/Tracing/HttpClient/TraceableResponseForV5.php">
<UndefinedInterfaceMethod occurrences="1">
<code>toStream</code>
Expand Down
89 changes: 89 additions & 0 deletions src/Tracing/Doctrine/DBAL/TracingDriverForV32.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Sentry\SentryBundle\Tracing\Doctrine\DBAL;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\API\ExceptionConverter;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;

/**
* This is a simple implementation of the {@see Driver} interface that decorates
* an existing driver to support distributed tracing capabilities. This implementation
* is compatible with all versions of Doctrine DBAL >= 3.2.
*
* @internal
*
* @phpstan-import-type Params from \Doctrine\DBAL\DriverManager as ConnectionParams
*/
final class TracingDriverForV32 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<T>
*/
public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager
{
return $this->decoratedDriver->getSchemaManager($conn, $platform);
}

/**
* {@inheritdoc}
*/
public function getExceptionConverter(): ExceptionConverter
{
return $this->decoratedDriver->getExceptionConverter();
}
}
9 changes: 8 additions & 1 deletion src/aliases.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Sentry\SentryBundle;

use Doctrine\DBAL\Exception\SchemaDoesNotExist;
use Doctrine\DBAL\Result;
use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapter;
use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapterForV2;
Expand All @@ -14,6 +15,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\TracingDriverForV32;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatement;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatementForV2;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingStatementForV3;
Expand Down Expand Up @@ -53,7 +55,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(TracingDriverForV32::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);
Expand Down
7 changes: 7 additions & 0 deletions tests/DoctrineTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Exception\SchemaDoesNotExist;
use PHPUnit\Framework\TestCase;

abstract class DoctrineTestCase extends TestCase
Expand All @@ -28,6 +29,12 @@ protected static function isDoctrineDBALVersion3Installed(): bool
&& !self::isDoctrineDBALVersion2Installed();
}

protected static function isDoctrineDBALVersion32Installed(): bool
{
return self::isDoctrineDBALInstalled()
&& class_exists(SchemaDoesNotExist::class);
}

protected static function isDoctrineBundlePackageInstalled(): bool
{
return class_exists(DoctrineBundle::class);
Expand Down
2 changes: 1 addition & 1 deletion tests/End2End/App/Command/MainCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class MainCommand extends Command
{
protected function configure()
protected function configure(): void
{
$this
->addOption('option1', null, InputOption::VALUE_NONE)
Expand Down
112 changes: 112 additions & 0 deletions tests/Tracing/Doctrine/DBAL/TracingDriverForV32Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

declare(strict_types=1);

namespace Sentry\SentryBundle\Tests\Tracing\Doctrine\DBAL;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\API\ExceptionConverter;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Connection as DriverConnectionInterface;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use PHPUnit\Framework\MockObject\MockObject;
use Sentry\SentryBundle\Tests\DoctrineTestCase;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverConnectionFactoryInterface;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverConnectionInterface;
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverForV32;

final class TracingDriverForV32Test extends DoctrineTestCase
{
/**
* @var MockObject&TracingDriverConnectionFactoryInterface
*/
private $connectionFactory;

public static function setUpBeforeClass(): void
{
if (!self::isDoctrineDBALVersion32Installed()) {
self::markTestSkipped('This test requires the version of the "doctrine/dbal" Composer package to be >= 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 TracingDriverForV32($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 TracingDriverForV32($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 TracingDriverForV32($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 TracingDriverForV32($this->connectionFactory, $decoratedDriver);

$this->assertSame($exceptionConverter, $driver->getExceptionConverter());
}
}
4 changes: 2 additions & 2 deletions tests/Tracing/Doctrine/DBAL/TracingDriverForV3Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ final class TracingDriverForV3Test extends DoctrineTestCase

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::isDoctrineDBALVersion3Installed() || self::isDoctrineDBALVersion32Installed()) {
self::markTestSkipped('This test requires the version of the "doctrine/dbal" Composer package to be >= 3.0 <= 3.2.');
}
}

Expand Down
3 changes: 3 additions & 0 deletions tests/Tracing/Doctrine/DBAL/TracingStatementForV3Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down