From 8fc9664b4544912f04b4bc9fee3aab4cb6a9358c Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Sun, 9 Feb 2025 17:41:09 -0500 Subject: [PATCH] Bump ORM requirements, fix translation walker handling of paginated queries --- CHANGELOG.md | 5 ++ composer.json | 4 +- phpstan-baseline.neon | 6 -- .../Query/TreeWalker/SoftDeleteableWalker.php | 4 +- src/Tool/ORM/Walker/CompatSqlOutputWalker.php | 59 ------------------- .../Walker/CompatSqlOutputWalkerForOrm2.php | 42 ------------- .../Walker/CompatSqlOutputWalkerForOrm3.php | 39 ------------ .../ORM/Walker/SqlWalkerCompatForOrm2.php | 25 ++++---- .../ORM/Walker/SqlWalkerCompatForOrm3.php | 16 ++--- .../Query/TreeWalker/TranslationWalker.php | 10 ++-- .../TranslationQueryWalkerTest.php | 15 +++++ 11 files changed, 50 insertions(+), 175 deletions(-) delete mode 100644 src/Tool/ORM/Walker/CompatSqlOutputWalker.php delete mode 100644 src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm2.php delete mode 100644 src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm3.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 04f92860fa..25ec72b502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ a release. --- ## [Unreleased] +### Changed +- Updated minimum versions for `doctrine/orm` to ^2.20 || ^3.3 + +### Fixed +- Regression with `doctrine/orm` ^2.20 || ^3.3 that caused the translation walker to produce queries with duplicated LIMIT clauses (issue #2917) ## [3.18.0] - 2025-02-01 ### Added diff --git a/composer.json b/composer.json index bc55266266..ac079cffcd 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,7 @@ "doctrine/dbal": "^3.7 || ^4.0", "doctrine/doctrine-bundle": "^2.3", "doctrine/mongodb-odm": "^2.3", - "doctrine/orm": "^2.14.0 || ^3.0", + "doctrine/orm": "^2.20 || ^3.3", "friendsofphp/php-cs-fixer": "^3.14.0", "nesbot/carbon": "^2.71 || ^3.0", "phpstan/phpstan": "^2.1.1", @@ -76,7 +76,7 @@ "doctrine/common": "<2.13 || >=4.0", "doctrine/dbal": "<3.7 || >=5.0", "doctrine/mongodb-odm": "<2.3 || >=3.0", - "doctrine/orm": "<2.14.0 || 2.16.0 || 2.16.1 || >=4.0" + "doctrine/orm": "<2.20 || >=3.0 <3.3 || >=4.0" }, "suggest": { "doctrine/mongodb-odm": "to use the extensions with the MongoDB ODM", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2bb87cb51e..a5fd58ccdf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -540,12 +540,6 @@ parameters: count: 1 path: src/Timestampable/Mapping/Driver/Yaml.php - - - message: '#^Call to an undefined static method Doctrine\\ORM\\Query\\SqlWalker\:\:getFinalizer\(\)\.$#' - identifier: staticMethod.notFound - count: 2 - path: src/Tool/ORM/Walker/CompatSqlOutputWalker.php - - message: '#^Access to an undefined property ProxyManager\\Proxy\\GhostObjectInterface&TObject of object\:\:\$identifier\.$#' identifier: property.notFound diff --git a/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php b/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php index cc67a72bf2..750b41521a 100644 --- a/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php +++ b/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php @@ -21,11 +21,11 @@ use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer; use Doctrine\ORM\Query\Exec\SingleTableDeleteUpdateExecutor; use Doctrine\ORM\Query\Exec\SqlFinalizer; +use Doctrine\ORM\Query\SqlOutputWalker; use Gedmo\Exception\RuntimeException; use Gedmo\Exception\UnexpectedValueException; use Gedmo\SoftDeleteable\Query\TreeWalker\Exec\MultiTableDeleteExecutor; use Gedmo\SoftDeleteable\SoftDeleteableListener; -use Gedmo\Tool\ORM\Walker\CompatSqlOutputWalker; use Gedmo\Tool\ORM\Walker\SqlWalkerCompat; /** @@ -38,7 +38,7 @@ * * @final since gedmo/doctrine-extensions 3.11 */ -class SoftDeleteableWalker extends CompatSqlOutputWalker +class SoftDeleteableWalker extends SqlOutputWalker { use SqlWalkerCompat; diff --git a/src/Tool/ORM/Walker/CompatSqlOutputWalker.php b/src/Tool/ORM/Walker/CompatSqlOutputWalker.php deleted file mode 100644 index 726dadea2a..0000000000 --- a/src/Tool/ORM/Walker/CompatSqlOutputWalker.php +++ /dev/null @@ -1,59 +0,0 @@ - http://www.gediminasm.org - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Gedmo\Tool\ORM\Walker; - -use Doctrine\ORM\Query\SqlOutputWalker; -use Doctrine\ORM\Query\SqlWalker; - -if (class_exists(SqlOutputWalker::class)) { - if ((new \ReflectionClass(SqlWalker::class))->getMethod('getExecutor')->hasReturnType()) { - /** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @internal - */ - abstract class CompatSqlOutputWalker extends SqlOutputWalker - { - use CompatSqlOutputWalkerForOrm3; - } - } else { - /** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @internal - */ - abstract class CompatSqlOutputWalker extends SqlOutputWalker - { - use CompatSqlOutputWalkerForOrm2; - } - } -} else { - if ((new \ReflectionClass(SqlWalker::class))->getMethod('getExecutor')->hasReturnType()) { - /** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @internal - */ - abstract class CompatSqlOutputWalker extends SqlWalker - { - use CompatSqlOutputWalkerForOrm3; - } - } else { - /** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @internal - */ - abstract class CompatSqlOutputWalker extends SqlWalker - { - use CompatSqlOutputWalkerForOrm2; - } - } -} diff --git a/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm2.php b/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm2.php deleted file mode 100644 index 9639aac526..0000000000 --- a/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm2.php +++ /dev/null @@ -1,42 +0,0 @@ - http://www.gediminasm.org - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Gedmo\Tool\ORM\Walker; - -use Doctrine\ORM\Query\AST\DeleteStatement; -use Doctrine\ORM\Query\AST\SelectStatement; -use Doctrine\ORM\Query\AST\UpdateStatement; -use Doctrine\ORM\Query\Exec\SqlFinalizer; -use Doctrine\ORM\Query\SqlOutputWalker; - -/** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @mixin SqlOutputWalker - * - * @internal - */ -trait CompatSqlOutputWalkerForOrm2 -{ - /** - * @param DeleteStatement|UpdateStatement|SelectStatement $AST - */ - public function getFinalizer($AST): SqlFinalizer - { - return $this->doGetFinalizerWithCompat($AST); - } - - /** - * @param DeleteStatement|UpdateStatement|SelectStatement $AST - */ - protected function doGetFinalizerWithCompat($AST): SqlFinalizer - { - return parent::getFinalizer($AST); - } -} diff --git a/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm3.php b/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm3.php deleted file mode 100644 index 52427fa90d..0000000000 --- a/src/Tool/ORM/Walker/CompatSqlOutputWalkerForOrm3.php +++ /dev/null @@ -1,39 +0,0 @@ - http://www.gediminasm.org - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Gedmo\Tool\ORM\Walker; - -use Doctrine\ORM\Query\AST\DeleteStatement; -use Doctrine\ORM\Query\AST\SelectStatement; -use Doctrine\ORM\Query\AST\UpdateStatement; -use Doctrine\ORM\Query\Exec\SqlFinalizer; -use Doctrine\ORM\Query\SqlOutputWalker; - -/** - * Helper trait to address compatibility issues between ORM 2.x and 3.x. - * - * @mixin SqlOutputWalker - * - * @internal - */ -trait CompatSqlOutputWalkerForOrm3 -{ - public function getFinalizer(DeleteStatement|UpdateStatement|SelectStatement $AST): SqlFinalizer - { - return $this->doGetFinalizerWithCompat($AST); - } - - /** - * @param DeleteStatement|UpdateStatement|SelectStatement $AST - */ - protected function doGetFinalizerWithCompat($AST): SqlFinalizer - { - return parent::getFinalizer($AST); - } -} diff --git a/src/Tool/ORM/Walker/SqlWalkerCompatForOrm2.php b/src/Tool/ORM/Walker/SqlWalkerCompatForOrm2.php index e810c749be..da24d2bf54 100644 --- a/src/Tool/ORM/Walker/SqlWalkerCompatForOrm2.php +++ b/src/Tool/ORM/Walker/SqlWalkerCompatForOrm2.php @@ -9,8 +9,8 @@ namespace Gedmo\Tool\ORM\Walker; -use Doctrine\ORM\Query\AST; use Doctrine\ORM\Query\AST\DeleteClause; +use Doctrine\ORM\Query\AST\DeleteStatement; use Doctrine\ORM\Query\AST\FromClause; use Doctrine\ORM\Query\AST\GroupByClause; use Doctrine\ORM\Query\AST\HavingClause; @@ -19,8 +19,10 @@ use Doctrine\ORM\Query\AST\SelectStatement; use Doctrine\ORM\Query\AST\SimpleSelectClause; use Doctrine\ORM\Query\AST\SubselectFromClause; +use Doctrine\ORM\Query\AST\UpdateStatement; use Doctrine\ORM\Query\AST\WhereClause; use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; +use Doctrine\ORM\Query\Exec\SqlFinalizer; use Doctrine\ORM\Query\SqlWalker; /** @@ -35,7 +37,7 @@ trait SqlWalkerCompatForOrm2 /** * Gets an executor that can be used to execute the result of this walker. * - * @param SelectStatement|AST\UpdateStatement|AST\DeleteStatement $statement + * @param SelectStatement|UpdateStatement|DeleteStatement $statement * * @return AbstractSqlExecutor */ @@ -45,15 +47,11 @@ public function getExecutor($statement) } /** - * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. - * - * @param SelectStatement $selectStatement - * - * @return string + * @param DeleteStatement|UpdateStatement|SelectStatement $AST */ - public function walkSelectStatement($selectStatement) + public function getFinalizer($AST): SqlFinalizer { - return $this->doWalkSelectStatementWithCompat($selectStatement); + return $this->doGetFinalizerWithCompat($AST); } /** @@ -169,16 +167,19 @@ public function walkWhereClause($whereClause) /** * Gets an executor that can be used to execute the result of this walker. * - * @param SelectStatement|AST\UpdateStatement|AST\DeleteStatement $statement + * @param SelectStatement|UpdateStatement|DeleteStatement $statement */ protected function doGetExecutorWithCompat($statement): AbstractSqlExecutor { return parent::getExecutor($statement); } - protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string + /** + * @param DeleteStatement|UpdateStatement|SelectStatement $AST + */ + protected function doGetFinalizerWithCompat($AST): SqlFinalizer { - return parent::walkSelectStatement($selectStatement); + return parent::getFinalizer($AST); } protected function doWalkSelectClauseWithCompat(SelectClause $selectClause): string diff --git a/src/Tool/ORM/Walker/SqlWalkerCompatForOrm3.php b/src/Tool/ORM/Walker/SqlWalkerCompatForOrm3.php index bb7b8289a9..cc33b706b8 100644 --- a/src/Tool/ORM/Walker/SqlWalkerCompatForOrm3.php +++ b/src/Tool/ORM/Walker/SqlWalkerCompatForOrm3.php @@ -9,7 +9,6 @@ namespace Gedmo\Tool\ORM\Walker; -use Doctrine\ORM\Query\AST; use Doctrine\ORM\Query\AST\DeleteClause; use Doctrine\ORM\Query\AST\DeleteStatement; use Doctrine\ORM\Query\AST\FromClause; @@ -23,6 +22,7 @@ use Doctrine\ORM\Query\AST\UpdateStatement; use Doctrine\ORM\Query\AST\WhereClause; use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; +use Doctrine\ORM\Query\Exec\SqlFinalizer; use Doctrine\ORM\Query\SqlWalker; /** @@ -42,12 +42,9 @@ public function getExecutor(SelectStatement|UpdateStatement|DeleteStatement $sta return $this->doGetExecutorWithCompat($statement); } - /** - * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. - */ - public function walkSelectStatement(SelectStatement $selectStatement): string + public function getFinalizer(DeleteStatement|UpdateStatement|SelectStatement $AST): SqlFinalizer { - return $this->doWalkSelectStatementWithCompat($selectStatement); + return $this->doGetFinalizerWithCompat($AST); } /** @@ -134,9 +131,12 @@ protected function doGetExecutorWithCompat($statement): AbstractSqlExecutor return parent::getExecutor($statement); } - protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string + /** + * @param DeleteStatement|UpdateStatement|SelectStatement $AST + */ + protected function doGetFinalizerWithCompat($AST): SqlFinalizer { - return parent::walkSelectStatement($selectStatement); + return parent::getFinalizer($AST); } protected function doWalkSelectClauseWithCompat(SelectClause $selectClause): string diff --git a/src/Translatable/Query/TreeWalker/TranslationWalker.php b/src/Translatable/Query/TreeWalker/TranslationWalker.php index 46a628934a..6d006fc25c 100644 --- a/src/Translatable/Query/TreeWalker/TranslationWalker.php +++ b/src/Translatable/Query/TreeWalker/TranslationWalker.php @@ -34,8 +34,8 @@ use Doctrine\ORM\Query\Exec\SingleSelectExecutor; use Doctrine\ORM\Query\Exec\SingleSelectSqlFinalizer; use Doctrine\ORM\Query\Exec\SqlFinalizer; +use Doctrine\ORM\Query\SqlOutputWalker; use Gedmo\Exception\RuntimeException; -use Gedmo\Tool\ORM\Walker\CompatSqlOutputWalker; use Gedmo\Tool\ORM\Walker\SqlWalkerCompat; use Gedmo\Translatable\Hydrator\ORM\ObjectHydrator; use Gedmo\Translatable\Hydrator\ORM\SimpleObjectHydrator; @@ -56,7 +56,7 @@ * * @final since gedmo/doctrine-extensions 3.11 */ -class TranslationWalker extends CompatSqlOutputWalker +class TranslationWalker extends SqlOutputWalker { use SqlWalkerCompat; @@ -155,12 +155,12 @@ protected function doGetFinalizerWithCompat($AST): SqlFinalizer } $this->prepareTranslatedComponents(); - return new SingleSelectSqlFinalizer($this->walkSelectStatement($AST)); + return new SingleSelectSqlFinalizer($this->createSqlForFinalizer($AST)); } - protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string + protected function createSqlForFinalizer(SelectStatement $selectStatement): string { - $result = parent::walkSelectStatement($selectStatement); + $result = parent::createSqlForFinalizer($selectStatement); if ([] === $this->translatedComponents) { return $result; } diff --git a/tests/Gedmo/Translatable/TranslationQueryWalkerTest.php b/tests/Gedmo/Translatable/TranslationQueryWalkerTest.php index 1eeb77a545..7e42c8207b 100644 --- a/tests/Gedmo/Translatable/TranslationQueryWalkerTest.php +++ b/tests/Gedmo/Translatable/TranslationQueryWalkerTest.php @@ -125,6 +125,21 @@ public function testJoinedWithStatements(): void static::assertSame('good', $comments[0]['subject']); } + /** + * @doesNotPerformAssertions + */ + public function testPaginatedQuery(): void + { + $this->populateMore(); + + $dql = 'SELECT a FROM '.Article::class.' a'; + $q = $this->em->createQuery($dql); + $q->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class); + $q->setFirstResult(0); + $q->setMaxResults(1); + $q->getResult(Query::HYDRATE_SIMPLEOBJECT); + } + public function testShouldSelectWithTranslationFallbackOnSimpleObjectHydration(): void { $this->em->getConfiguration()->addCustomHydrationMode(