From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Tools/Pagination/LimitSubqueryWalker.php | 155 +++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php (limited to 'vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php') diff --git a/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php new file mode 100644 index 0000000..3fb0eee --- /dev/null +++ b/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php @@ -0,0 +1,155 @@ +fromClause->identificationVariableDeclarations; + $fromRoot = reset($from); + $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; + $rootClass = $this->getMetadataForDqlAlias($rootAlias); + + $this->validate($selectStatement); + $identifier = $rootClass->getSingleIdentifierFieldName(); + + if (isset($rootClass->associationMappings[$identifier])) { + throw new RuntimeException('Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator.'); + } + + $query = $this->_getQuery(); + + $query->setHint( + self::IDENTIFIER_TYPE, + Type::getType($rootClass->fieldMappings[$identifier]->type), + ); + + $query->setHint(self::FORCE_DBAL_TYPE_CONVERSION, true); + + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, + $rootAlias, + $identifier, + ); + + $pathExpression->type = PathExpression::TYPE_STATE_FIELD; + + $selectStatement->selectClause->selectExpressions = [new SelectExpression($pathExpression, '_dctrn_id')]; + $selectStatement->selectClause->isDistinct = ($query->getHints()[Paginator::HINT_ENABLE_DISTINCT] ?? true) === true; + + if (! isset($selectStatement->orderByClause)) { + return; + } + + $queryComponents = $this->getQueryComponents(); + foreach ($selectStatement->orderByClause->orderByItems as $item) { + if ($item->expression instanceof PathExpression) { + $selectStatement->selectClause->selectExpressions[] = new SelectExpression( + $this->createSelectExpressionItem($item->expression), + '_dctrn_ord' . $this->aliasCounter++, + ); + + continue; + } + + if (is_string($item->expression) && isset($queryComponents[$item->expression])) { + $qComp = $queryComponents[$item->expression]; + + if (isset($qComp['resultVariable'])) { + $selectStatement->selectClause->selectExpressions[] = new SelectExpression( + $qComp['resultVariable'], + $item->expression, + ); + } + } + } + } + + /** + * Validate the AST to ensure that this walker is able to properly manipulate it. + */ + private function validate(SelectStatement $AST): void + { + // Prevent LimitSubqueryWalker from being used with queries that include + // a limit, a fetched to-many join, and an order by condition that + // references a column from the fetch joined table. + $queryComponents = $this->getQueryComponents(); + $query = $this->_getQuery(); + $from = $AST->fromClause->identificationVariableDeclarations; + $fromRoot = reset($from); + + if ( + $query instanceof Query + && $query->getMaxResults() !== null + && $AST->orderByClause + && count($fromRoot->joins) + ) { + // Check each orderby item. + // TODO: check complex orderby items too... + foreach ($AST->orderByClause->orderByItems as $orderByItem) { + $expression = $orderByItem->expression; + if ( + $orderByItem->expression instanceof PathExpression + && isset($queryComponents[$expression->identificationVariable]) + ) { + $queryComponent = $queryComponents[$expression->identificationVariable]; + if ( + isset($queryComponent['parent']) + && isset($queryComponent['relation']) + && $queryComponent['relation']->isToMany() + ) { + throw new RuntimeException('Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers.'); + } + } + } + } + } + + /** + * Retrieve either an IdentityFunction (IDENTITY(u.assoc)) or a state field (u.name). + * + * @return IdentityFunction|PathExpression + */ + private function createSelectExpressionItem(PathExpression $pathExpression): Node + { + if ($pathExpression->type === PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) { + $identity = new IdentityFunction('identity'); + + $identity->pathExpression = clone $pathExpression; + + return $identity; + } + + return clone $pathExpression; + } +} -- cgit v1.2.3