From f953e34d3696d93a5b052c7e204669d739bdb1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Adamczewski?= Date: Fri, 11 Aug 2023 09:46:49 +0200 Subject: [PATCH] Add support of older versions of Doctrine/Dbal library #175 (#176) Added implementation for QueryBuilder proxy supporting doctrine/dbal ^2.12.0|^3.0 (#175) --- composer.json | 2 +- packages/Dbal/composer.json | 2 +- .../src/Compatibility/QueryBuilderProxy.php | 224 ++++++++++++++++++ .../src/DocumentStore/DbalDocumentStore.php | 5 +- .../Recoverability/DbalDeadLetterHandler.php | 10 +- packages/Dbal/tests/DbalMessagingTestCase.php | 2 +- .../OrderService.php | 3 +- .../Fixture/Transaction/OrderService.php | 2 +- 8 files changed, 239 insertions(+), 11 deletions(-) create mode 100644 packages/Dbal/src/Compatibility/QueryBuilderProxy.php diff --git a/composer.json b/composer.json index c18134d8c..ce2c1d903 100644 --- a/composer.json +++ b/composer.json @@ -96,7 +96,7 @@ }, "require": { "php": "^8.0", - "doctrine/dbal": "^3.3.7", + "doctrine/dbal": "^2.12.0|^3.0", "doctrine/persistence": "^2.5", "enqueue/amqp-ext": "^0.10.18", "enqueue/dbal": "^0.10.17", diff --git a/packages/Dbal/composer.json b/packages/Dbal/composer.json index ffdbdd5e0..c702a5d97 100644 --- a/packages/Dbal/composer.json +++ b/packages/Dbal/composer.json @@ -32,7 +32,7 @@ "require": { "ecotone/enqueue": "~1.96.0", "enqueue/dbal": "^0.10.17", - "doctrine/dbal": "^3.3.7" + "doctrine/dbal": "^2.12.0|^3.0" }, "require-dev": { "phpunit/phpunit": "^9.5", diff --git a/packages/Dbal/src/Compatibility/QueryBuilderProxy.php b/packages/Dbal/src/Compatibility/QueryBuilderProxy.php new file mode 100644 index 000000000..ca7ecfbab --- /dev/null +++ b/packages/Dbal/src/Compatibility/QueryBuilderProxy.php @@ -0,0 +1,224 @@ + + * + * Simple proxy class to keep the QueryBuilder API compatible with Doctrine DBAL 2.10 and 3.0 + * All the parent methods need to be implemented in order to intercept and pass to the wrapped instance. + * Class supports execution of various fetch methods directly from query object that was added in version 3.1 + * + * @see https://github.com/doctrine/dbal/blob/3.6.x/UPGRADE.md#upgrade-to-31 + */ +final class QueryBuilderProxy extends QueryBuilder +{ + public function __construct(private QueryBuilder $queryBuilder) + { + } + + // override all public methods from parent class with empty body + public function select($select = null) + { + $this->queryBuilder->{__FUNCTION__}(...func_get_args()); + + return $this; + } + + public function from($from, $alias = null) + { + $this->queryBuilder->{__FUNCTION__}($from, $alias); + + return $this; + } + + public function addSelect($select = null) + { + $this->queryBuilder->{__FUNCTION__}(...func_get_args()); + + return $this; + } + + public function delete($delete = null, $alias = null) + { + $this->queryBuilder->{__FUNCTION__}($delete, $alias); + + return $this; + } + + public function update($update = null, $alias = null) + { + $this->queryBuilder->{__FUNCTION__}($update, $alias); + + return $this; + } + + public function set($key, $value) + { + $this->queryBuilder->{__FUNCTION__}($key, $value); + + return $this; + } + + public function where($predicates) + { + $this->queryBuilder->{__FUNCTION__}($predicates); + + return $this; + } + + public function andWhere($where) + { + $this->queryBuilder->{__FUNCTION__}($where); + + return $this; + } + + public function orWhere($where) + { + $this->queryBuilder->{__FUNCTION__}($where); + + return $this; + } + + public function groupBy($groupBy) + { + $this->queryBuilder->{__FUNCTION__}($groupBy); + + return $this; + } + + public function addGroupBy($groupBy) + { + $this->queryBuilder->{__FUNCTION__}($groupBy); + + return $this; + } + + public function having($having) + { + $this->queryBuilder->{__FUNCTION__}($having); + + return $this; + } + + public function setFirstResult($firstResult) + { + $this->queryBuilder->{__FUNCTION__}($firstResult); + + return $this; + } + + public function setMaxResults($maxResults) + { + $this->queryBuilder->{__FUNCTION__}($maxResults); + + return $this; + } + + public function setParameter($key, $value, $type = null) + { + $this->queryBuilder->{__FUNCTION__}($key, $value, $type); + + return $this; + } + + public function setParameters(array $params, array $types = []) + { + $this->queryBuilder->{__FUNCTION__}($params, $types); + + return $this; + } + + public function __clone() + { + $this->queryBuilder->{__FUNCTION__}(); + + return $this; + } + + public function __toString() + { + $this->queryBuilder->{__FUNCTION__}(); + + return $this; + } + + public function expr() + { + $this->queryBuilder->{__FUNCTION__}(); + + return $this; + } + + public function resetQueryParts($queryPartNames = null) + { + $this->queryBuilder->{__FUNCTION__}($queryPartNames); + + return $this; + } + + public function getQueryPart($queryPartName) + { + $this->queryBuilder->{__FUNCTION__}($queryPartName); + + return $this; + } + + public function getSQL() + { + return $this->queryBuilder->{__FUNCTION__}(); + } + + public function getType() + { + return $this->queryBuilder->{__FUNCTION__}(); + } + + public function getState() + { + return $this->queryBuilder->{__FUNCTION__}(); + } + + public function execute() + { + return $this->queryBuilder->{__FUNCTION__}(); + } + + public function executeQuery(): Result + { + $name = method_exists($this->queryBuilder, __FUNCTION__) ? __FUNCTION__ : 'execute'; + + return $this->queryBuilder->{$name}(); + } + + public function executeStatement(): int + { + $name = method_exists($this->queryBuilder, __FUNCTION__) ? __FUNCTION__ : 'execute'; + + return $this->queryBuilder->{$name}(); + } + + public function __call($name, $arguments) + { + switch ($name) { + case 'fetchAllAssociativeIndexed': + case 'fetchAllKeyValue': + case 'fetchAllNumeric': + case 'fetchAssociative': + case 'fetchNumeric': + case 'fetchAllAssociative': + case 'fetchFirstColumn': + case 'fetchOne': + return $this->queryBuilder->execute()->$name(...$arguments); + } + + throw new \InvalidArgumentException(sprintf("Not supported proxy method: %s", $name)); + } +} \ No newline at end of file diff --git a/packages/Dbal/src/DocumentStore/DbalDocumentStore.php b/packages/Dbal/src/DocumentStore/DbalDocumentStore.php index 15b3719eb..f3a677b42 100644 --- a/packages/Dbal/src/DocumentStore/DbalDocumentStore.php +++ b/packages/Dbal/src/DocumentStore/DbalDocumentStore.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Types; +use Ecotone\Dbal\Compatibility\QueryBuilderProxy; use Ecotone\Enqueue\CachedConnectionFactory; use Ecotone\Messaging\Conversion\ConversionService; use Ecotone\Messaging\Conversion\MediaType; @@ -160,7 +161,7 @@ public function countDocuments(string $collectionName): int return 0; } - $select = $this->getConnection()->createQueryBuilder() + $select = (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->select('COUNT(document_id)') ->from($this->getTableName()) ->andWhere('collection = :collection') @@ -272,7 +273,7 @@ private function updateDocumentInternally(object|array|string $document, string private function getDocumentsFor(string $collectionName): \Doctrine\DBAL\Query\QueryBuilder { - return $this->getConnection()->createQueryBuilder() + return (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->select('document', 'document_type') ->from($this->getTableName()) ->andWhere('collection = :collection') diff --git a/packages/Dbal/src/Recoverability/DbalDeadLetterHandler.php b/packages/Dbal/src/Recoverability/DbalDeadLetterHandler.php index 4a4edf2e5..354bcff7d 100644 --- a/packages/Dbal/src/Recoverability/DbalDeadLetterHandler.php +++ b/packages/Dbal/src/Recoverability/DbalDeadLetterHandler.php @@ -8,6 +8,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Types; +use Ecotone\Dbal\Compatibility\QueryBuilderProxy; use Ecotone\Messaging\Conversion\ConversionService; use Ecotone\Messaging\Gateway\MessagingEntrypoint; use Ecotone\Messaging\Handler\Recoverability\ErrorContext; @@ -47,7 +48,7 @@ public function list(int $limit, int $offset): array return []; } - $messages = $this->getConnection()->createQueryBuilder() + $messages = (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->select('*') ->from($this->getTableName()) ->setMaxResults($limit) @@ -64,7 +65,8 @@ public function list(int $limit, int $offset): array public function show(string $messageId, ?MessageChannel $replyChannel = null): Message { $this->initialize(); - $message = $this->getConnection()->createQueryBuilder() + + $message = (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->select('*') ->from($this->getTableName()) ->andWhere('message_id = :messageId') @@ -96,7 +98,7 @@ public function count(): int return 0; } - return (int)$this->getConnection()->createQueryBuilder() + return (int) (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->select('count(*)') ->from($this->getTableName()) ->executeQuery() @@ -283,7 +285,7 @@ private function replyWithoutInitialization(string $messageId, MessagingEntrypoi private function deleteGivenMessage(array|string $messageId): void { - $this->getConnection()->createQueryBuilder() + (new QueryBuilderProxy($this->getConnection()->createQueryBuilder())) ->delete($this->getTableName()) ->andWhere('message_id = :messageId') ->setParameter('messageId', $messageId, Types::TEXT) diff --git a/packages/Dbal/tests/DbalMessagingTestCase.php b/packages/Dbal/tests/DbalMessagingTestCase.php index a14863acc..672d1d784 100644 --- a/packages/Dbal/tests/DbalMessagingTestCase.php +++ b/packages/Dbal/tests/DbalMessagingTestCase.php @@ -65,7 +65,7 @@ public function setUp(): void protected function checkIfTableExists(Connection $connection, string $table): bool { - $schemaManager = $connection->createSchemaManager(); + $schemaManager = method_exists($connection, 'getSchemaManager') ? $connection->getSchemaManager() : $connection->createSchemaManager(); return $schemaManager->tablesExist([$table]); } diff --git a/packages/Dbal/tests/Fixture/AsynchronousChannelTransaction/OrderService.php b/packages/Dbal/tests/Fixture/AsynchronousChannelTransaction/OrderService.php index c56b725cd..46ac636c4 100644 --- a/packages/Dbal/tests/Fixture/AsynchronousChannelTransaction/OrderService.php +++ b/packages/Dbal/tests/Fixture/AsynchronousChannelTransaction/OrderService.php @@ -44,7 +44,8 @@ public function register(string $order, OrderRegisteringGateway $orderRegisterin #[CommandHandler('order.register_with_table_creation', 'orderRegister2')] public function registerWithTableCreation(string $order, OrderRegisteringGateway $orderRegisteringGateway, #[Reference(DbalConnectionFactory::class)] ConnectionFactory $connection): void { - $schemaManager = $connection->createContext()->getDbalConnection()->createSchemaManager(); + $connection = $connection->createContext()->getDbalConnection(); + $schemaManager = method_exists($connection, 'getSchemaManager') ? $connection->getSchemaManager() : $connection->createSchemaManager(); if ($schemaManager->tablesExist(['test_table'])) { $schemaManager->dropTable('test_table'); diff --git a/packages/Dbal/tests/Fixture/Transaction/OrderService.php b/packages/Dbal/tests/Fixture/Transaction/OrderService.php index 8efc340ca..9fcd4006a 100644 --- a/packages/Dbal/tests/Fixture/Transaction/OrderService.php +++ b/packages/Dbal/tests/Fixture/Transaction/OrderService.php @@ -73,7 +73,7 @@ public function hasOrder(#[Reference(DbalConnectionFactory::class)] ManagerRegis private function doesTableExists(\Doctrine\DBAL\Connection $connection) { - $schemaManager = $connection->createSchemaManager(); + $schemaManager = method_exists($connection, 'getSchemaManager') ? $connection->getSchemaManager() : $connection->createSchemaManager(); return $schemaManager->tablesExist(['orders']); }