From 018761afff5578de3e30a14b071849036eceba8f Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Tue, 28 May 2024 17:31:29 -0400 Subject: [PATCH] Add an internal trait to allow cross-version compatibility for ORM SQL walkers --- phpstan.neon.dist | 2 + .../Query/TreeWalker/SoftDeleteableWalker.php | 27 ++- src/Tool/ORM/Walker/SqlWalkerCompat.php | 20 ++ src/Tool/ORM/Walker/orm-2.php | 228 ++++++++++++++++++ src/Tool/ORM/Walker/orm-3.php | 186 ++++++++++++++ .../Query/TreeWalker/TranslationWalker.php | 98 +++----- 6 files changed, 479 insertions(+), 82 deletions(-) create mode 100644 src/Tool/ORM/Walker/SqlWalkerCompat.php create mode 100644 src/Tool/ORM/Walker/orm-2.php create mode 100644 src/Tool/ORM/Walker/orm-3.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fb646d6ae3..ac12149b6c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -22,3 +22,5 @@ parameters: excludePaths: # Generates non-ignorable errors like " Parameter #1 $method (string) of method Gedmo\Tree\Entity\Repository\NestedTreeRepository::__call() is not contravariant with parameter #1 $method (mixed) of method Doctrine\ORM\EntityRepository::__call()." - src/Tool/ORM/Repository/EntityRepositoryCompat.php + # Compat file for ORM 3, causes analysis errors with ORM 2 + - src/Tool/ORM/Walker/orm-3.php diff --git a/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php b/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php index 9e9d779f06..010330eab5 100644 --- a/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php +++ b/src/SoftDeleteable/Query/TreeWalker/SoftDeleteableWalker.php @@ -15,6 +15,8 @@ use Doctrine\ORM\Mapping\QuoteStrategy; use Doctrine\ORM\Query\AST\DeleteClause; use Doctrine\ORM\Query\AST\DeleteStatement; +use Doctrine\ORM\Query\AST\SelectStatement; +use Doctrine\ORM\Query\AST\UpdateStatement; use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; use Doctrine\ORM\Query\Exec\SingleTableDeleteUpdateExecutor; use Doctrine\ORM\Query\SqlWalker; @@ -22,6 +24,7 @@ use Gedmo\Exception\UnexpectedValueException; use Gedmo\SoftDeleteable\Query\TreeWalker\Exec\MultiTableDeleteExecutor; use Gedmo\SoftDeleteable\SoftDeleteableListener; +use Gedmo\Tool\ORM\Walker\SqlWalkerCompat; /** * This SqlWalker is needed when you need to use a DELETE DQL query. @@ -35,6 +38,8 @@ */ class SoftDeleteableWalker extends SqlWalker { + use SqlWalkerCompat; + /** * @var Connection * @@ -94,30 +99,30 @@ public function __construct($query, $parserResult, array $queryComponents) } /** - * @return AbstractSqlExecutor + * @param SelectStatement|UpdateStatement|DeleteStatement $statement + * + * @throws UnexpectedValueException when an unsupported AST statement is given */ - public function getExecutor($AST) + protected function doGetExecutorWithCompat($statement): AbstractSqlExecutor { switch (true) { - case $AST instanceof DeleteStatement: - assert(class_exists($AST->deleteClause->abstractSchemaName)); + case $statement instanceof DeleteStatement: + assert(class_exists($statement->deleteClause->abstractSchemaName)); - $primaryClass = $this->getEntityManager()->getClassMetadata($AST->deleteClause->abstractSchemaName); + $primaryClass = $this->getEntityManager()->getClassMetadata($statement->deleteClause->abstractSchemaName); return $primaryClass->isInheritanceTypeJoined() - ? new MultiTableDeleteExecutor($AST, $this, $this->meta, $this->getConnection()->getDatabasePlatform(), $this->configuration) - : new SingleTableDeleteUpdateExecutor($AST, $this); + ? new MultiTableDeleteExecutor($statement, $this, $this->meta, $this->getConnection()->getDatabasePlatform(), $this->configuration) + : new SingleTableDeleteUpdateExecutor($statement, $this); default: throw new UnexpectedValueException('SoftDeleteable walker should be used only on delete statement'); } } /** - * Change a DELETE clause for an UPDATE clause - * - * @return string the SQL + * Changes a DELETE clause into an UPDATE clause for a soft-deleteable entity. */ - public function walkDeleteClause(DeleteClause $deleteClause) + protected function doWalkDeleteClauseWithCompat(DeleteClause $deleteClause): string { $em = $this->getEntityManager(); diff --git a/src/Tool/ORM/Walker/SqlWalkerCompat.php b/src/Tool/ORM/Walker/SqlWalkerCompat.php new file mode 100644 index 0000000000..5dceefc019 --- /dev/null +++ b/src/Tool/ORM/Walker/SqlWalkerCompat.php @@ -0,0 +1,20 @@ + 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\SqlWalker; + +if ((new \ReflectionClass(SqlWalker::class))->getMethod('getExecutor')->hasReturnType()) { + // ORM 3.x + require_once __DIR__.'/orm-3.php'; +} else { + // ORM 2.x + require_once __DIR__.'/orm-2.php'; +} diff --git a/src/Tool/ORM/Walker/orm-2.php b/src/Tool/ORM/Walker/orm-2.php new file mode 100644 index 0000000000..d8fd670790 --- /dev/null +++ b/src/Tool/ORM/Walker/orm-2.php @@ -0,0 +1,228 @@ + 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; +use Doctrine\ORM\Query\AST\DeleteClause; +use Doctrine\ORM\Query\AST\FromClause; +use Doctrine\ORM\Query\AST\GroupByClause; +use Doctrine\ORM\Query\AST\HavingClause; +use Doctrine\ORM\Query\AST\OrderByClause; +use Doctrine\ORM\Query\AST\SelectClause; +use Doctrine\ORM\Query\AST\SelectStatement; +use Doctrine\ORM\Query\AST\SimpleSelectClause; +use Doctrine\ORM\Query\AST\SubselectFromClause; +use Doctrine\ORM\Query\AST\WhereClause; +use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; +use Doctrine\ORM\Query\SqlWalker; + +/** + * Helper trait to address compatibility issues between ORM 2.x and 3.x. + * + * @mixin SqlWalker + * + * @internal + */ +trait SqlWalkerCompat +{ + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @param SelectStatement|AST\UpdateStatement|AST\DeleteStatement $statement + * + * @return AbstractSqlExecutor + */ + public function getExecutor($statement) + { + return $this->doGetExecutorWithCompat($statement); + } + + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + * + * @param SelectStatement $selectStatement + * + * @return string + */ + public function walkSelectStatement($selectStatement) + { + return $this->doWalkSelectStatementWithCompat($selectStatement); + } + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + * + * @param SelectClause $selectClause + * + * @return string + */ + public function walkSelectClause($selectClause) + { + return $this->doWalkSelectClauseWithCompat($selectClause); + } + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + * + * @param FromClause $fromClause + * + * @return string + */ + public function walkFromClause($fromClause) + { + return $this->doWalkFromClauseWithCompat($fromClause); + } + + /** + * Walks down a OrderByClause AST node, thereby generating the appropriate SQL. + * + * @param OrderByClause $orderByClause + * + * @return string + */ + public function walkOrderByClause($orderByClause) + { + return $this->doWalkOrderByClauseWithCompat($orderByClause); + } + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + * + * @param HavingClause $havingClause + * + * @return string + */ + public function walkHavingClause($havingClause) + { + return $this->doWalkHavingClauseWithCompat($havingClause); + } + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + * + * @param SubselectFromClause $subselectFromClause + * + * @return string + */ + public function walkSubselectFromClause($subselectFromClause) + { + return $this->doWalkSubselectFromClauseWithCompat($subselectFromClause); + } + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectClause $simpleSelectClause + * + * @return string + */ + public function walkSimpleSelectClause($simpleSelectClause) + { + return $this->doWalkSimpleSelectClauseWithCompat($simpleSelectClause); + } + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + * + * @param GroupByClause $groupByClause + * + * @return string + */ + public function walkGroupByClause($groupByClause) + { + return $this->doWalkGroupByClauseWithCompat($groupByClause); + } + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + * + * @param DeleteClause $deleteClause + * + * @return string + */ + public function walkDeleteClause($deleteClause) + { + return $this->doWalkDeleteClauseWithCompat($deleteClause); + } + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * + * WhereClause or not, the appropriate discriminator sql is added. + * + * @param WhereClause|null $whereClause + * + * @return string + */ + public function walkWhereClause($whereClause) + { + return $this->doWalkWhereClauseWithCompat($whereClause); + } + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @param SelectStatement|AST\UpdateStatement|AST\DeleteStatement $statement + */ + protected function doGetExecutorWithCompat($statement): AbstractSqlExecutor + { + return parent::getExecutor($statement); + } + + protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string + { + return parent::walkSelectStatement($selectStatement); + } + + protected function doWalkSelectClauseWithCompat(SelectClause $selectClause): string + { + return parent::walkSelectClause($selectClause); + } + + protected function doWalkFromClauseWithCompat(FromClause $fromClause): string + { + return parent::walkFromClause($fromClause); + } + + protected function doWalkOrderByClauseWithCompat(OrderByClause $orderByClause): string + { + return parent::walkOrderByClause($orderByClause); + } + + protected function doWalkHavingClauseWithCompat(HavingClause $havingClause): string + { + return parent::walkHavingClause($havingClause); + } + + protected function doWalkSubselectFromClauseWithCompat(SubselectFromClause $subselectFromClause): string + { + return parent::walkSubselectFromClause($subselectFromClause); + } + + protected function doWalkSimpleSelectClauseWithCompat(SimpleSelectClause $simpleSelectClause): string + { + return parent::walkSimpleSelectClause($simpleSelectClause); + } + + protected function doWalkGroupByClauseWithCompat(GroupByClause $groupByClause): string + { + return parent::walkGroupByClause($groupByClause); + } + + protected function doWalkDeleteClauseWithCompat(DeleteClause $deleteClause): string + { + return parent::walkDeleteClause($deleteClause); + } + + protected function doWalkWhereClauseWithCompat(?WhereClause $whereClause): string + { + return parent::walkWhereClause($whereClause); + } +} diff --git a/src/Tool/ORM/Walker/orm-3.php b/src/Tool/ORM/Walker/orm-3.php new file mode 100644 index 0000000000..380d64ff5a --- /dev/null +++ b/src/Tool/ORM/Walker/orm-3.php @@ -0,0 +1,186 @@ + 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; +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; +use Doctrine\ORM\Query\AST\OrderByClause; +use Doctrine\ORM\Query\AST\SelectClause; +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\SqlWalker; + +/** + * Helper trait to address compatibility issues between ORM 2.x and 3.x. + * + * @mixin SqlWalker + * + * @internal + */ +trait SqlWalkerCompat +{ + /** + * Gets an executor that can be used to execute the result of this walker. + */ + public function getExecutor(SelectStatement|UpdateStatement|DeleteStatement $statement): AbstractSqlExecutor + { + return $this->doGetExecutorWithCompat($statement); + } + + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + */ + public function walkSelectStatement(SelectStatement $selectStatement): string + { + return $this->doWalkSelectStatementWithCompat($selectStatement); + } + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + */ + public function walkSelectClause(SelectClause $selectClause): string + { + return $this->doWalkSelectClauseWithCompat($selectClause); + } + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + */ + public function walkFromClause(FromClause $fromClause): string + { + return $this->doWalkFromClauseWithCompat($fromClause); + } + + /** + * Walks down a OrderByClause AST node, thereby generating the appropriate SQL. + */ + public function walkOrderByClause(OrderByClause $orderByClause): string + { + return $this->doWalkOrderByClauseWithCompat($orderByClause); + } + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + */ + public function walkHavingClause(HavingClause $havingClause): string + { + return $this->doWalkHavingClauseWithCompat($havingClause); + } + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + */ + public function walkSubselectFromClause(SubselectFromClause $subselectFromClause): string + { + return $this->doWalkSubselectFromClauseWithCompat($subselectFromClause); + } + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + */ + public function walkSimpleSelectClause(SimpleSelectClause $simpleSelectClause): string + { + return $this->doWalkSimpleSelectClauseWithCompat($simpleSelectClause); + } + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + */ + public function walkGroupByClause(GroupByClause $groupByClause): string + { + return $this->doWalkGroupByClauseWithCompat($groupByClause); + } + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + */ + public function walkDeleteClause(DeleteClause $deleteClause): string + { + return $this->doWalkDeleteClauseWithCompat($deleteClause); + } + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * + * WhereClause or not, the appropriate discriminator sql is added. + */ + public function walkWhereClause(?WhereClause $whereClause): string + { + return $this->doWalkWhereClauseWithCompat($whereClause); + } + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @param SelectStatement|UpdateStatement|DeleteStatement $statement + */ + protected function doGetExecutorWithCompat($statement): AbstractSqlExecutor + { + return parent::getExecutor($statement); + } + + protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string + { + return parent::walkSelectStatement($selectStatement); + } + + protected function doWalkSelectClauseWithCompat(SelectClause $selectClause): string + { + return parent::walkSelectClause($selectClause); + } + + protected function doWalkFromClauseWithCompat(FromClause $fromClause): string + { + return parent::walkFromClause($fromClause); + } + + protected function doWalkOrderByClauseWithCompat(OrderByClause $orderByClause): string + { + return parent::walkOrderByClause($orderByClause); + } + + protected function doWalkHavingClauseWithCompat(HavingClause $havingClause): string + { + return parent::walkHavingClause($havingClause); + } + + protected function doWalkSubselectFromClauseWithCompat(SubselectFromClause $subselectFromClause): string + { + return parent::walkSubselectFromClause($subselectFromClause); + } + + protected function doWalkSimpleSelectClauseWithCompat(SimpleSelectClause $simpleSelectClause): string + { + return parent::walkSimpleSelectClause($simpleSelectClause); + } + + protected function doWalkGroupByClauseWithCompat(GroupByClause $groupByClause): string + { + return parent::walkGroupByClause($groupByClause); + } + + protected function doWalkDeleteClauseWithCompat(DeleteClause $deleteClause): string + { + return parent::walkDeleteClause($deleteClause); + } + + protected function doWalkWhereClauseWithCompat(?WhereClause $whereClause): string + { + return parent::walkWhereClause($whereClause); + } +} diff --git a/src/Translatable/Query/TreeWalker/TranslationWalker.php b/src/Translatable/Query/TreeWalker/TranslationWalker.php index e09bdfe1a6..7f83f2779c 100644 --- a/src/Translatable/Query/TreeWalker/TranslationWalker.php +++ b/src/Translatable/Query/TreeWalker/TranslationWalker.php @@ -17,14 +17,21 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query; use Doctrine\ORM\Query\AST\FromClause; +use Doctrine\ORM\Query\AST\GroupByClause; +use Doctrine\ORM\Query\AST\HavingClause; use Doctrine\ORM\Query\AST\Join; use Doctrine\ORM\Query\AST\Node; +use Doctrine\ORM\Query\AST\OrderByClause; use Doctrine\ORM\Query\AST\RangeVariableDeclaration; +use Doctrine\ORM\Query\AST\SelectClause; use Doctrine\ORM\Query\AST\SelectStatement; +use Doctrine\ORM\Query\AST\SimpleSelectClause; use Doctrine\ORM\Query\AST\SubselectFromClause; +use Doctrine\ORM\Query\AST\WhereClause; use Doctrine\ORM\Query\Exec\SingleSelectExecutor; use Doctrine\ORM\Query\SqlWalker; use Gedmo\Exception\RuntimeException; +use Gedmo\Tool\ORM\Walker\SqlWalkerCompat; use Gedmo\Translatable\Hydrator\ORM\ObjectHydrator; use Gedmo\Translatable\Hydrator\ORM\SimpleObjectHydrator; use Gedmo\Translatable\Mapping\Event\Adapter\ORM as TranslatableEventAdapter; @@ -46,6 +53,8 @@ */ class TranslationWalker extends SqlWalker { + use SqlWalkerCompat; + /** * Name for translation fallback hint * @@ -131,12 +140,9 @@ public function getExecutor($AST) return new SingleSelectExecutor($AST, $this); } - /** - * @return string - */ - public function walkSelectStatement(SelectStatement $AST) + protected function doWalkSelectStatementWithCompat(SelectStatement $selectStatement): string { - $result = parent::walkSelectStatement($AST); + $result = parent::walkSelectStatement($selectStatement); if ([] === $this->translatedComponents) { return $result; } @@ -161,94 +167,44 @@ public function walkSelectStatement(SelectStatement $AST) return $result; } - /** - * @return string - */ - public function walkSelectClause($selectClause) + protected function doWalkSelectClauseWithCompat(SelectClause $selectClause): string { - $result = parent::walkSelectClause($selectClause); - - return $this->replace($this->replacements, $result); + return $this->replace($this->replacements, parent::walkSelectClause($selectClause)); } - /** - * @return string - */ - public function walkFromClause($fromClause) + protected function doWalkFromClauseWithCompat(FromClause $fromClause): string { - $result = parent::walkFromClause($fromClause); - $result .= $this->joinTranslations($fromClause); - - return $result; - } - - /** - * @return string - */ - public function walkWhereClause($whereClause) - { - $result = parent::walkWhereClause($whereClause); - - return $this->replace($this->replacements, $result); + return parent::walkFromClause($fromClause).$this->joinTranslations($fromClause); } - /** - * @return string - */ - public function walkHavingClause($havingClause) + protected function doWalkWhereClauseWithCompat(?WhereClause $whereClause): string { - $result = parent::walkHavingClause($havingClause); - - return $this->replace($this->replacements, $result); + return $this->replace($this->replacements, parent::walkWhereClause($whereClause)); } - /** - * @return string - */ - public function walkOrderByClause($orderByClause) + protected function doWalkHavingClauseWithCompat(HavingClause $havingClause): string { - $result = parent::walkOrderByClause($orderByClause); - - return $this->replace($this->replacements, $result); + return $this->replace($this->replacements, parent::walkHavingClause($havingClause)); } - /** - * @return string - */ - public function walkSubselect($subselect) + protected function doWalkOrderByClauseWithCompat(OrderByClause $orderByClause): string { - return parent::walkSubselect($subselect); + return $this->replace($this->replacements, parent::walkOrderByClause($orderByClause)); } - /** - * @return string - */ - public function walkSubselectFromClause($subselectFromClause) + protected function doWalkSubselectFromClauseWithCompat(SubselectFromClause $subselectFromClause): string { - $result = parent::walkSubselectFromClause($subselectFromClause); - $result .= $this->joinTranslations($subselectFromClause); - - return $result; + return parent::walkSubselectFromClause($subselectFromClause).$this->joinTranslations($subselectFromClause); } - /** - * @return string - */ - public function walkSimpleSelectClause($simpleSelectClause) + protected function doWalkSimpleSelectClauseWithCompat(SimpleSelectClause $simpleSelectClause): string { - $result = parent::walkSimpleSelectClause($simpleSelectClause); - - return $this->replace($this->replacements, $result); + return $this->replace($this->replacements, parent::walkSimpleSelectClause($simpleSelectClause)); } - /** - * @return string - */ - public function walkGroupByClause($groupByClause) + protected function doWalkGroupByClauseWithCompat(GroupByClause $groupByClause): string { - $result = parent::walkGroupByClause($groupByClause); - - return $this->replace($this->replacements, $result); + return $this->replace($this->replacements, parent::walkGroupByClause($groupByClause)); } /**