diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57786979..69107972 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,7 @@ jobs: - { php: '8.1', packages: 'aws/aws-sdk-php:^3.158', phpspec: 'spec/Gaufrette/Adapter/AwsS3Spec.php' } - { php: '8.1', packages: 'google/apiclient:^2.12', phpspec: 'spec/Gaufrette/Adapter/GoogleCloudStorageSpec.php' } - { php: '8.1', packages: 'doctrine/dbal:^2.3', phpspec: 'spec/Gaufrette/Adapter/DoctrineDbalSpec.php' } + - { php: '8.1', packages: 'doctrine/dbal:^3.4', phpspec: 'spec/Gaufrette/Adapter/DoctrineDbalSpec.php' } - { php: '8.1', packages: 'league/flysystem:^1.0', phpspec: 'spec/Gaufrette/Adapter/FlysystemSpec.php' } - { php: '8.1', packages: 'microsoft/azure-storage-blob:^1.0', phpspec: 'spec/Gaufrette/Adapter/AzureBlobStore' } - { php: '8.1', packages: 'mongodb/mongodb:^1.1', phpspec: 'spec/Gaufrette/Adapter/GridFSSpec.php' } diff --git a/Makefile b/Makefile index fc29c04e..b4942d83 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ docker.all-deps: docker.deps ## Install dependencies docker/run-task php${PHP_VERSION} composer require --no-update \ aws/aws-sdk-php:^3.158 \ google/apiclient:^2.12 \ - doctrine/dbal:^2.3 \ + doctrine/dbal:^3.4 \ league/flysystem:^1.0 \ microsoft/azure-storage-blob:^1.0 \ phpseclib/phpseclib:^2.0 \ @@ -67,7 +67,7 @@ require-all-legacy: # kept for compatibility with the old CI config, to be remov composer require --no-update \ aws/aws-sdk-php:^3.158 \ google/apiclient:^2.12 \ - doctrine/dbal:^2.3 \ + doctrine/dbal:^3.4 \ league/flysystem:^1.0 \ microsoft/azure-storage-blob:^1.0 \ phpseclib/phpseclib:^2.0 \ diff --git a/spec/Gaufrette/Adapter/DoctrineDbalSpec.php b/spec/Gaufrette/Adapter/DoctrineDbalSpec.php index 091ee157..4e723e14 100644 --- a/spec/Gaufrette/Adapter/DoctrineDbalSpec.php +++ b/spec/Gaufrette/Adapter/DoctrineDbalSpec.php @@ -6,7 +6,7 @@ require_once 'functions.php'; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Result; use PhpSpec\ObjectBehavior; use Prophecy\Argument; @@ -46,13 +46,18 @@ function it_checks_if_file_exists(Connection $connection) return sprintf('"%s"', $argument[0]); }); + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection - ->fetchColumn('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(12); $this->exists('filename')->shouldReturn(true); $connection - ->fetchColumn('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(0); $this->exists('filename')->shouldReturn(false); } @@ -67,8 +72,14 @@ function it_writes_to_new_file(Connection $connection) ->will(function ($argument) { return sprintf('"%s"', $argument[0]); }); + + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection - ->fetchColumn('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(false); $connection ->insert( @@ -90,13 +101,18 @@ function it_writes_to_new_file(Connection $connection) */ function it_write_file(Connection $connection) { + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection ->quoteIdentifier(Argument::any()) ->will(function ($argument) { return sprintf('"%s"', $argument[0]); }); $connection - ->fetchColumn('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT COUNT("key") FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(true); $connection ->update( @@ -120,13 +136,18 @@ function it_write_file(Connection $connection) */ function it_reads_file(Connection $connection) { + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection ->quoteIdentifier(Argument::any()) ->will(function ($argument) { return sprintf('"%s"', $argument[0]); }); $connection - ->fetchColumn('SELECT "content" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT "content" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn('some content'); $this->read('filename')->shouldReturn('some content'); @@ -137,13 +158,18 @@ function it_reads_file(Connection $connection) */ function it_calculates_checksum(Connection $connection) { + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection ->quoteIdentifier(Argument::any()) ->will(function ($argument) { return sprintf('"%s"', $argument[0]); }); $connection - ->fetchColumn('SELECT "checksum" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT "checksum" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(1234); $this->checksum('filename')->shouldReturn(1234); @@ -154,13 +180,18 @@ function it_calculates_checksum(Connection $connection) */ function it_gets_mtime(Connection $connection) { + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + $connection ->quoteIdentifier(Argument::any()) ->will(function ($argument) { return sprintf('"%s"', $argument[0]); }); $connection - ->fetchColumn('SELECT "mtime" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) + ->$method('SELECT "mtime" FROM "someTableName" WHERE "key" = :key', ['key' => 'filename']) ->willReturn(1234); $this->mtime('filename')->shouldReturn(1234); @@ -194,11 +225,19 @@ function it_renames_file(Connection $connection) /** * @param \Doctrine\DBAL\Connection $connection - * @param \Doctrine\DBAL\Statement $stmt */ - function it_get_keys(Connection $connection, Statement $stmt) + function it_get_keys(Connection $connection, $result) { - $stmt->fetchAll(\PDO::FETCH_COLUMN)->willReturn(['filename', 'filename1', 'filename2']); + if (class_exists(Result::class)) { + // dbal 3.x + $result->beADoubleOf(Result::class); + $result->fetchFirstColumn()->willReturn(['filename', 'filename1', 'filename2']); + } else { + // BC layer for dbal 2.x + $result->beADoubleOf(\Doctrine\DBAL\Statement::class); + $result->fetchAll(\PDO::FETCH_COLUMN)->willReturn(['filename', 'filename1', 'filename2']); + } + $connection ->quoteIdentifier(Argument::any()) ->will(function ($argument) { @@ -206,7 +245,7 @@ function it_get_keys(Connection $connection, Statement $stmt) }); $connection ->executeQuery('SELECT "key" FROM "someTableName"') - ->willReturn($stmt); + ->willReturn($result); $this->keys()->shouldReturn(['filename', 'filename1', 'filename2']); } diff --git a/src/Gaufrette/Adapter/DoctrineDbal.php b/src/Gaufrette/Adapter/DoctrineDbal.php index 337b1de6..77066d2f 100644 --- a/src/Gaufrette/Adapter/DoctrineDbal.php +++ b/src/Gaufrette/Adapter/DoctrineDbal.php @@ -2,6 +2,7 @@ namespace Gaufrette\Adapter; +use Doctrine\DBAL\Result; use Gaufrette\Adapter; use Gaufrette\Util; use Doctrine\DBAL\Connection; @@ -52,6 +53,12 @@ public function keys() $this->getQuotedTable() )); + if (class_exists(Result::class)) { + // dbal 3.x + return $stmt->fetchFirstColumn(); + } + + // BC layer for dbal 2.x return $stmt->fetchAll(\PDO::FETCH_COLUMN); } @@ -88,7 +95,12 @@ public function checksum($key) */ public function exists($key) { - return (boolean) $this->connection->fetchColumn( + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, $method)) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + + return (boolean) $this->connection->$method( sprintf( 'SELECT COUNT(%s) FROM %s WHERE %s = :key', $this->getQuotedColumn('key'), @@ -153,7 +165,12 @@ public function isDirectory($key) private function getColumnValue($key, $column) { - $value = $this->connection->fetchColumn( + $method = 'fetchOne'; // dbal 3.x + if (!method_exists(Connection::class, $method)) { + $method = 'fetchColumn'; // BC layer for dbal 2.x + } + + $value = $this->connection->$method( sprintf( 'SELECT %s FROM %s WHERE %s = :key', $this->getQuotedColumn($column), @@ -173,7 +190,12 @@ public function listKeys($prefix = '') { $prefix = trim($prefix); - $keys = $this->connection->fetchAll( + $method = 'fetchAllAssociative'; // dbal 3.x + if (!method_exists(Connection::class, 'fetchAllAssociative')) { + $method = 'fetchAll'; // BC layer for dbal 2.x + } + + $keys = $this->connection->$method( sprintf( 'SELECT %s AS _key FROM %s WHERE %s LIKE :pattern', $this->getQuotedColumn('key'), diff --git a/tests/Gaufrette/Functional/Adapter/DoctrineDbalTest.php b/tests/Gaufrette/Functional/Adapter/DoctrineDbalTest.php index df53f63c..aa9d8a39 100644 --- a/tests/Gaufrette/Functional/Adapter/DoctrineDbalTest.php +++ b/tests/Gaufrette/Functional/Adapter/DoctrineDbalTest.php @@ -29,7 +29,14 @@ protected function setUp(): void $schema = $this->connection->getSchemaManager()->createSchema(); $table = $schema->createTable('gaufrette'); - $table->addColumn('key', 'string', ['unique' => true]); + $column = $table->addColumn('key', 'string'); + if (method_exists($column, 'setPlatformOption')) { + // dbal 3.4+ + $column->setPlatformOption('unique', true); + } else { + // BC layer dbal 2.x + $column->setUnique(true); + } $table->addColumn('content', 'blob'); $table->addColumn('mtime', 'integer'); $table->addColumn('checksum', 'string', ['length' => 32]);