From 05e38eadbeb3de19e5b26003c2b401e00bb71df4 Mon Sep 17 00:00:00 2001 From: polo Date: Sun, 18 Oct 2026 00:08:23 +0200 Subject: =?UTF-8?q?sortie=20de=20vendor=20du=20d=C3=A9p=C3=B4t,=20oubli=20?= =?UTF-8?q?dans=20config-template.ini?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../orm/src/Tools/Pagination/CountOutputWalker.php | 125 ----- .../orm/src/Tools/Pagination/CountWalker.php | 68 --- .../Exception/RowNumberOverFunctionNotEnabled.php | 16 - .../Tools/Pagination/LimitSubqueryOutputWalker.php | 544 --------------------- .../src/Tools/Pagination/LimitSubqueryWalker.php | 155 ------ .../orm/src/Tools/Pagination/Paginator.php | 263 ---------- .../orm/src/Tools/Pagination/RootTypeWalker.php | 48 -- .../src/Tools/Pagination/RowNumberOverFunction.php | 40 -- .../orm/src/Tools/Pagination/WhereInWalker.php | 116 ----- 9 files changed, 1375 deletions(-) delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/CountOutputWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryOutputWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/Paginator.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php delete mode 100644 vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php (limited to 'vendor/doctrine/orm/src/Tools/Pagination') diff --git a/vendor/doctrine/orm/src/Tools/Pagination/CountOutputWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/CountOutputWalker.php deleted file mode 100644 index c7f31db..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/CountOutputWalker.php +++ /dev/null @@ -1,125 +0,0 @@ - FROM ()) - * - * Works with composite keys but cannot deal with queries that have multiple - * root entities (e.g. `SELECT f, b from Foo, Bar`) - * - * Note that the ORDER BY clause is not removed. Many SQL implementations (e.g. MySQL) - * are able to cache subqueries. By keeping the ORDER BY clause intact, the limitSubQuery - * that will most likely be executed next can be read from the native SQL cache. - * - * @psalm-import-type QueryComponent from Parser - */ -class CountOutputWalker extends SqlWalker -{ - private readonly AbstractPlatform $platform; - private readonly ResultSetMapping $rsm; - - /** - * {@inheritDoc} - */ - public function __construct(Query $query, ParserResult $parserResult, array $queryComponents) - { - $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); - $this->rsm = $parserResult->getResultSetMapping(); - - parent::__construct($query, $parserResult, $queryComponents); - } - - public function walkSelectStatement(SelectStatement $selectStatement): string - { - if ($this->platform instanceof SQLServerPlatform) { - $selectStatement->orderByClause = null; - } - - $sql = parent::walkSelectStatement($selectStatement); - - if ($selectStatement->groupByClause) { - return sprintf( - 'SELECT COUNT(*) AS dctrn_count FROM (%s) dctrn_table', - $sql, - ); - } - - // Find out the SQL alias of the identifier column of the root entity - // It may be possible to make this work with multiple root entities but that - // would probably require issuing multiple queries or doing a UNION SELECT - // so for now, It's not supported. - - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $rootIdentifier = $rootClass->identifier; - - // For every identifier, find out the SQL alias by combing through the ResultSetMapping - $sqlIdentifier = []; - foreach ($rootIdentifier as $property) { - if (isset($rootClass->fieldMappings[$property])) { - foreach (array_keys($this->rsm->fieldMappings, $property, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - - if (isset($rootClass->associationMappings[$property])) { - $association = $rootClass->associationMappings[$property]; - assert($association->isToOneOwningSide()); - $joinColumn = $association->joinColumns[0]->name; - - foreach (array_keys($this->rsm->metaMappings, $joinColumn, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - } - - if (count($rootIdentifier) !== count($sqlIdentifier)) { - throw new RuntimeException(sprintf( - 'Not all identifier properties can be found in the ResultSetMapping: %s', - implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))), - )); - } - - // Build the counter query - return sprintf( - 'SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT %s FROM (%s) dctrn_result) dctrn_table', - implode(', ', $sqlIdentifier), - $sql, - ); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php deleted file mode 100644 index d212943..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/CountWalker.php +++ /dev/null @@ -1,68 +0,0 @@ -havingClause) { - throw new RuntimeException('Cannot count query that uses a HAVING clause. Use the output walkers for pagination'); - } - - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - $pathType = PathExpression::TYPE_STATE_FIELD; - if (isset($rootClass->associationMappings[$identifierFieldName])) { - $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - } - - $pathExpression = new PathExpression( - PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, - $rootAlias, - $identifierFieldName, - ); - $pathExpression->type = $pathType; - - $distinct = $this->_getQuery()->getHint(self::HINT_DISTINCT); - $selectStatement->selectClause->selectExpressions = [ - new SelectExpression( - new AggregateExpression('count', $pathExpression, $distinct), - null, - ), - ]; - - // ORDER BY is not needed, only increases query execution through unnecessary sorting. - $selectStatement->orderByClause = null; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php b/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php deleted file mode 100644 index 0e3da93..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/Exception/RowNumberOverFunctionNotEnabled.php +++ /dev/null @@ -1,16 +0,0 @@ - FROM () LIMIT x OFFSET y - * - * Works with composite keys but cannot deal with queries that have multiple - * root entities (e.g. `SELECT f, b from Foo, Bar`) - * - * @psalm-import-type QueryComponent from Parser - */ -class LimitSubqueryOutputWalker extends SqlWalker -{ - private const ORDER_BY_PATH_EXPRESSION = '/(? */ - private array $orderByPathExpressions = []; - - /** - * We don't want to add path expressions from sub-selects into the select clause of the containing query. - * This state flag simply keeps track on whether we are walking on a subquery or not - */ - private bool $inSubSelect = false; - - /** - * Stores various parameters that are otherwise unavailable - * because Doctrine\ORM\Query\SqlWalker keeps everything private without - * accessors. - * - * {@inheritDoc} - */ - public function __construct( - Query $query, - ParserResult $parserResult, - array $queryComponents, - ) { - $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); - $this->rsm = $parserResult->getResultSetMapping(); - - // Reset limit and offset - $this->firstResult = $query->getFirstResult(); - $this->maxResults = $query->getMaxResults(); - $query->setFirstResult(0)->setMaxResults(null); - - $this->em = $query->getEntityManager(); - $this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy(); - - parent::__construct($query, $parserResult, $queryComponents); - } - - /** - * Check if the platform supports the ROW_NUMBER window function. - */ - private function platformSupportsRowNumber(): bool - { - return $this->platform instanceof PostgreSQLPlatform - || $this->platform instanceof SQLServerPlatform - || $this->platform instanceof OraclePlatform - || $this->platform instanceof DB2Platform - || (method_exists($this->platform, 'supportsRowNumberFunction') - && $this->platform->supportsRowNumberFunction()); - } - - /** - * Rebuilds a select statement's order by clause for use in a - * ROW_NUMBER() OVER() expression. - */ - private function rebuildOrderByForRowNumber(SelectStatement $AST): void - { - $orderByClause = $AST->orderByClause; - $selectAliasToExpressionMap = []; - // Get any aliases that are available for select expressions. - foreach ($AST->selectClause->selectExpressions as $selectExpression) { - $selectAliasToExpressionMap[$selectExpression->fieldIdentificationVariable] = $selectExpression->expression; - } - - // Rebuild string orderby expressions to use the select expression they're referencing - foreach ($orderByClause->orderByItems as $orderByItem) { - if (is_string($orderByItem->expression) && isset($selectAliasToExpressionMap[$orderByItem->expression])) { - $orderByItem->expression = $selectAliasToExpressionMap[$orderByItem->expression]; - } - } - - $func = new RowNumberOverFunction('dctrn_rownum'); - $func->orderByClause = $AST->orderByClause; - $AST->selectClause->selectExpressions[] = new SelectExpression($func, 'dctrn_rownum', true); - - // No need for an order by clause, we'll order by rownum in the outer query. - $AST->orderByClause = null; - } - - public function walkSelectStatement(SelectStatement $selectStatement): string - { - if ($this->platformSupportsRowNumber()) { - return $this->walkSelectStatementWithRowNumber($selectStatement); - } - - return $this->walkSelectStatementWithoutRowNumber($selectStatement); - } - - /** - * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT. - * This method is for use with platforms which support ROW_NUMBER. - * - * @throws RuntimeException - */ - public function walkSelectStatementWithRowNumber(SelectStatement $AST): string - { - $hasOrderBy = false; - $outerOrderBy = ' ORDER BY dctrn_minrownum ASC'; - $orderGroupBy = ''; - if ($AST->orderByClause instanceof OrderByClause) { - $hasOrderBy = true; - $this->rebuildOrderByForRowNumber($AST); - } - - $innerSql = $this->getInnerSQL($AST); - - $sqlIdentifier = $this->getSQLIdentifier($AST); - - if ($hasOrderBy) { - $orderGroupBy = ' GROUP BY ' . implode(', ', $sqlIdentifier); - $sqlIdentifier[] = 'MIN(' . $this->walkResultVariable('dctrn_rownum') . ') AS dctrn_minrownum'; - } - - // Build the counter query - $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $innerSql, - ); - - if ($hasOrderBy) { - $sql .= $orderGroupBy . $outerOrderBy; - } - - // Apply the limit and offset. - $sql = $this->platform->modifyLimitQuery( - $sql, - $this->maxResults, - $this->firstResult, - ); - - // Add the columns to the ResultSetMapping. It's not really nice but - // it works. Preferably I'd clear the RSM or simply create a new one - // but that is not possible from inside the output walker, so we dirty - // up the one we have. - foreach ($sqlIdentifier as $property => $alias) { - $this->rsm->addScalarResult($alias, $property); - } - - return $sql; - } - - /** - * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT. - * This method is for platforms which DO NOT support ROW_NUMBER. - * - * @throws RuntimeException - */ - public function walkSelectStatementWithoutRowNumber(SelectStatement $AST, bool $addMissingItemsFromOrderByToSelect = true): string - { - // We don't want to call this recursively! - if ($AST->orderByClause instanceof OrderByClause && $addMissingItemsFromOrderByToSelect) { - // In the case of ordering a query by columns from joined tables, we - // must add those columns to the select clause of the query BEFORE - // the SQL is generated. - $this->addMissingItemsFromOrderByToSelect($AST); - } - - // Remove order by clause from the inner query - // It will be re-appended in the outer select generated by this method - $orderByClause = $AST->orderByClause; - $AST->orderByClause = null; - - $innerSql = $this->getInnerSQL($AST); - - $sqlIdentifier = $this->getSQLIdentifier($AST); - - // Build the counter query - $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $innerSql, - ); - - // https://github.com/doctrine/orm/issues/2630 - $sql = $this->preserveSqlOrdering($sqlIdentifier, $innerSql, $sql, $orderByClause); - - // Apply the limit and offset. - $sql = $this->platform->modifyLimitQuery( - $sql, - $this->maxResults, - $this->firstResult, - ); - - // Add the columns to the ResultSetMapping. It's not really nice but - // it works. Preferably I'd clear the RSM or simply create a new one - // but that is not possible from inside the output walker, so we dirty - // up the one we have. - foreach ($sqlIdentifier as $property => $alias) { - $this->rsm->addScalarResult($alias, $property); - } - - // Restore orderByClause - $AST->orderByClause = $orderByClause; - - return $sql; - } - - /** - * Finds all PathExpressions in an AST's OrderByClause, and ensures that - * the referenced fields are present in the SelectClause of the passed AST. - */ - private function addMissingItemsFromOrderByToSelect(SelectStatement $AST): void - { - $this->orderByPathExpressions = []; - - // We need to do this in another walker because otherwise we'll end up - // polluting the state of this one. - $walker = clone $this; - - // This will populate $orderByPathExpressions via - // LimitSubqueryOutputWalker::walkPathExpression, which will be called - // as the select statement is walked. We'll end up with an array of all - // path expressions referenced in the query. - $walker->walkSelectStatementWithoutRowNumber($AST, false); - $orderByPathExpressions = $walker->getOrderByPathExpressions(); - - // Get a map of referenced identifiers to field names. - $selects = []; - foreach ($orderByPathExpressions as $pathExpression) { - assert($pathExpression->field !== null); - $idVar = $pathExpression->identificationVariable; - $field = $pathExpression->field; - if (! isset($selects[$idVar])) { - $selects[$idVar] = []; - } - - $selects[$idVar][$field] = true; - } - - // Loop the select clause of the AST and exclude items from $select - // that are already being selected in the query. - foreach ($AST->selectClause->selectExpressions as $selectExpression) { - if ($selectExpression instanceof SelectExpression) { - $idVar = $selectExpression->expression; - if (! is_string($idVar)) { - continue; - } - - $field = $selectExpression->fieldIdentificationVariable; - if ($field === null) { - // No need to add this select, as we're already fetching the whole object. - unset($selects[$idVar]); - } else { - unset($selects[$idVar][$field]); - } - } - } - - // Add select items which were not excluded to the AST's select clause. - foreach ($selects as $idVar => $fields) { - $AST->selectClause->selectExpressions[] = new SelectExpression($idVar, null, true); - } - } - - /** - * Generates new SQL for statements with an order by clause - * - * @param mixed[] $sqlIdentifier - */ - private function preserveSqlOrdering( - array $sqlIdentifier, - string $innerSql, - string $sql, - OrderByClause|null $orderByClause, - ): string { - // If the sql statement has an order by clause, we need to wrap it in a new select distinct statement - if (! $orderByClause) { - return $sql; - } - - // now only select distinct identifier - return sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result', - implode(', ', $sqlIdentifier), - $this->recreateInnerSql($orderByClause, $sqlIdentifier, $innerSql), - ); - } - - /** - * Generates a new SQL statement for the inner query to keep the correct sorting - * - * @param mixed[] $identifiers - */ - private function recreateInnerSql( - OrderByClause $orderByClause, - array $identifiers, - string $innerSql, - ): string { - [$searchPatterns, $replacements] = $this->generateSqlAliasReplacements(); - $orderByItems = []; - - foreach ($orderByClause->orderByItems as $orderByItem) { - // Walk order by item to get string representation of it and - // replace path expressions in the order by clause with their column alias - $orderByItemString = preg_replace( - $searchPatterns, - $replacements, - $this->walkOrderByItem($orderByItem), - ); - - $orderByItems[] = $orderByItemString; - $identifier = substr($orderByItemString, 0, strrpos($orderByItemString, ' ')); - - if (! in_array($identifier, $identifiers, true)) { - $identifiers[] = $identifier; - } - } - - return $sql = sprintf( - 'SELECT DISTINCT %s FROM (%s) dctrn_result_inner ORDER BY %s', - implode(', ', $identifiers), - $innerSql, - implode(', ', $orderByItems), - ); - } - - /** - * @return string[][] - * @psalm-return array{0: list, 1: list} - */ - private function generateSqlAliasReplacements(): array - { - $aliasMap = $searchPatterns = $replacements = $metadataList = []; - - // Generate DQL alias -> SQL table alias mapping - foreach (array_keys($this->rsm->aliasMap) as $dqlAlias) { - $metadataList[$dqlAlias] = $class = $this->getMetadataForDqlAlias($dqlAlias); - $aliasMap[$dqlAlias] = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - } - - // Generate search patterns for each field's path expression in the order by clause - foreach ($this->rsm->fieldMappings as $fieldAlias => $fieldName) { - $dqlAliasForFieldAlias = $this->rsm->columnOwnerMap[$fieldAlias]; - $class = $metadataList[$dqlAliasForFieldAlias]; - - // If the field is from a joined child table, we won't be ordering on it. - if (! isset($class->fieldMappings[$fieldName])) { - continue; - } - - $fieldMapping = $class->fieldMappings[$fieldName]; - - // Get the proper column name as will appear in the select list - $columnName = $this->quoteStrategy->getColumnName( - $fieldName, - $metadataList[$dqlAliasForFieldAlias], - $this->em->getConnection()->getDatabasePlatform(), - ); - - // Get the SQL table alias for the entity and field - $sqlTableAliasForFieldAlias = $aliasMap[$dqlAliasForFieldAlias]; - - if (isset($fieldMapping->declared) && $fieldMapping->declared !== $class->name) { - // Field was declared in a parent class, so we need to get the proper SQL table alias - // for the joined parent table. - $otherClassMetadata = $this->em->getClassMetadata($fieldMapping->declared); - - if (! $otherClassMetadata->isMappedSuperclass) { - $sqlTableAliasForFieldAlias = $this->getSQLTableAlias($otherClassMetadata->getTableName(), $dqlAliasForFieldAlias); - } - } - - // Compose search and replace patterns - $searchPatterns[] = sprintf(self::ORDER_BY_PATH_EXPRESSION, $sqlTableAliasForFieldAlias, $columnName); - $replacements[] = $fieldAlias; - } - - return [$searchPatterns, $replacements]; - } - - /** - * getter for $orderByPathExpressions - * - * @return list - */ - public function getOrderByPathExpressions(): array - { - return $this->orderByPathExpressions; - } - - /** - * @throws OptimisticLockException - * @throws QueryException - */ - private function getInnerSQL(SelectStatement $AST): string - { - // Set every select expression as visible(hidden = false) to - // make $AST have scalar mappings properly - this is relevant for referencing selected - // fields from outside the subquery, for example in the ORDER BY segment - $hiddens = []; - - foreach ($AST->selectClause->selectExpressions as $idx => $expr) { - $hiddens[$idx] = $expr->hiddenAliasResultVariable; - $expr->hiddenAliasResultVariable = false; - } - - $innerSql = parent::walkSelectStatement($AST); - - // Restore hiddens - foreach ($AST->selectClause->selectExpressions as $idx => $expr) { - $expr->hiddenAliasResultVariable = $hiddens[$idx]; - } - - return $innerSql; - } - - /** @return string[] */ - private function getSQLIdentifier(SelectStatement $AST): array - { - // Find out the SQL alias of the identifier column of the root entity. - // It may be possible to make this work with multiple root entities but that - // would probably require issuing multiple queries or doing a UNION SELECT. - // So for now, it's not supported. - - // Get the root entity and alias from the AST fromClause. - $from = $AST->fromClause->identificationVariableDeclarations; - if (count($from) !== 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $rootIdentifier = $rootClass->identifier; - - // For every identifier, find out the SQL alias by combing through the ResultSetMapping - $sqlIdentifier = []; - foreach ($rootIdentifier as $property) { - if (isset($rootClass->fieldMappings[$property])) { - foreach (array_keys($this->rsm->fieldMappings, $property, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - - if (isset($rootClass->associationMappings[$property])) { - $association = $rootClass->associationMappings[$property]; - assert($association->isToOneOwningSide()); - $joinColumn = $association->joinColumns[0]->name; - - foreach (array_keys($this->rsm->metaMappings, $joinColumn, true) as $alias) { - if ($this->rsm->columnOwnerMap[$alias] === $rootAlias) { - $sqlIdentifier[$property] = $alias; - } - } - } - } - - if (count($sqlIdentifier) === 0) { - throw new RuntimeException('The Paginator does not support Queries which only yield ScalarResults.'); - } - - if (count($rootIdentifier) !== count($sqlIdentifier)) { - throw new RuntimeException(sprintf( - 'Not all identifier properties can be found in the ResultSetMapping: %s', - implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))), - )); - } - - return $sqlIdentifier; - } - - public function walkPathExpression(PathExpression $pathExpr): string - { - if (! $this->inSubSelect && ! $this->platformSupportsRowNumber() && ! in_array($pathExpr, $this->orderByPathExpressions, true)) { - $this->orderByPathExpressions[] = $pathExpr; - } - - return parent::walkPathExpression($pathExpr); - } - - public function walkSubSelect(Subselect $subselect): string - { - $this->inSubSelect = true; - - $sql = parent::walkSubselect($subselect); - - $this->inSubSelect = false; - - return $sql; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php deleted file mode 100644 index 3fb0eee..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/LimitSubqueryWalker.php +++ /dev/null @@ -1,155 +0,0 @@ -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; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php b/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php deleted file mode 100644 index db1b34d..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/Paginator.php +++ /dev/null @@ -1,263 +0,0 @@ - - */ -class Paginator implements Countable, IteratorAggregate -{ - use SQLResultCasing; - - public const HINT_ENABLE_DISTINCT = 'paginator.distinct.enable'; - - private readonly Query $query; - private bool|null $useOutputWalkers = null; - private int|null $count = null; - - /** @param bool $fetchJoinCollection Whether the query joins a collection (true by default). */ - public function __construct( - Query|QueryBuilder $query, - private readonly bool $fetchJoinCollection = true, - ) { - if ($query instanceof QueryBuilder) { - $query = $query->getQuery(); - } - - $this->query = $query; - } - - /** - * Returns the query. - */ - public function getQuery(): Query - { - return $this->query; - } - - /** - * Returns whether the query joins a collection. - * - * @return bool Whether the query joins a collection. - */ - public function getFetchJoinCollection(): bool - { - return $this->fetchJoinCollection; - } - - /** - * Returns whether the paginator will use an output walker. - */ - public function getUseOutputWalkers(): bool|null - { - return $this->useOutputWalkers; - } - - /** - * Sets whether the paginator will use an output walker. - * - * @return $this - */ - public function setUseOutputWalkers(bool|null $useOutputWalkers): static - { - $this->useOutputWalkers = $useOutputWalkers; - - return $this; - } - - public function count(): int - { - if ($this->count === null) { - try { - $this->count = (int) array_sum(array_map('current', $this->getCountQuery()->getScalarResult())); - } catch (NoResultException) { - $this->count = 0; - } - } - - return $this->count; - } - - /** - * {@inheritDoc} - * - * @psalm-return Traversable - */ - public function getIterator(): Traversable - { - $offset = $this->query->getFirstResult(); - $length = $this->query->getMaxResults(); - - if ($this->fetchJoinCollection && $length !== null) { - $subQuery = $this->cloneQuery($this->query); - - if ($this->useOutputWalker($subQuery)) { - $subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); - } else { - $this->appendTreeWalker($subQuery, LimitSubqueryWalker::class); - $this->unbindUnusedQueryParams($subQuery); - } - - $subQuery->setFirstResult($offset)->setMaxResults($length); - - $foundIdRows = $subQuery->getScalarResult(); - - // don't do this for an empty id array - if ($foundIdRows === []) { - return new ArrayIterator([]); - } - - $whereInQuery = $this->cloneQuery($this->query); - $ids = array_map('current', $foundIdRows); - - $this->appendTreeWalker($whereInQuery, WhereInWalker::class); - $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_HAS_IDS, true); - $whereInQuery->setFirstResult(0)->setMaxResults(null); - $whereInQuery->setCacheable($this->query->isCacheable()); - - $databaseIds = $this->convertWhereInIdentifiersToDatabaseValues($ids); - $whereInQuery->setParameter(WhereInWalker::PAGINATOR_ID_ALIAS, $databaseIds); - - $result = $whereInQuery->getResult($this->query->getHydrationMode()); - } else { - $result = $this->cloneQuery($this->query) - ->setMaxResults($length) - ->setFirstResult($offset) - ->setCacheable($this->query->isCacheable()) - ->getResult($this->query->getHydrationMode()); - } - - return new ArrayIterator($result); - } - - private function cloneQuery(Query $query): Query - { - $cloneQuery = clone $query; - - $cloneQuery->setParameters(clone $query->getParameters()); - $cloneQuery->setCacheable(false); - - foreach ($query->getHints() as $name => $value) { - $cloneQuery->setHint($name, $value); - } - - return $cloneQuery; - } - - /** - * Determines whether to use an output walker for the query. - */ - private function useOutputWalker(Query $query): bool - { - if ($this->useOutputWalkers === null) { - return (bool) $query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) === false; - } - - return $this->useOutputWalkers; - } - - /** - * Appends a custom tree walker to the tree walkers hint. - * - * @psalm-param class-string $walkerClass - */ - private function appendTreeWalker(Query $query, string $walkerClass): void - { - $hints = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS); - - if ($hints === false) { - $hints = []; - } - - $hints[] = $walkerClass; - $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints); - } - - /** - * Returns Query prepared to count. - */ - private function getCountQuery(): Query - { - $countQuery = $this->cloneQuery($this->query); - - if (! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) { - $countQuery->setHint(CountWalker::HINT_DISTINCT, true); - } - - if ($this->useOutputWalker($countQuery)) { - $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win - - $rsm = new ResultSetMapping(); - $rsm->addScalarResult($this->getSQLResultCasing($platform, 'dctrn_count'), 'count'); - - $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, CountOutputWalker::class); - $countQuery->setResultSetMapping($rsm); - } else { - $this->appendTreeWalker($countQuery, CountWalker::class); - $this->unbindUnusedQueryParams($countQuery); - } - - $countQuery->setFirstResult(0)->setMaxResults(null); - - return $countQuery; - } - - private function unbindUnusedQueryParams(Query $query): void - { - $parser = new Parser($query); - $parameterMappings = $parser->parse()->getParameterMappings(); - /** @var Collection|Parameter[] $parameters */ - $parameters = $query->getParameters(); - - foreach ($parameters as $key => $parameter) { - $parameterName = $parameter->getName(); - - if (! (isset($parameterMappings[$parameterName]) || array_key_exists($parameterName, $parameterMappings))) { - unset($parameters[$key]); - } - } - - $query->setParameters($parameters); - } - - /** - * @param mixed[] $identifiers - * - * @return mixed[] - */ - private function convertWhereInIdentifiersToDatabaseValues(array $identifiers): array - { - $query = $this->cloneQuery($this->query); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, RootTypeWalker::class); - - $connection = $this->query->getEntityManager()->getConnection(); - $type = $query->getSQL(); - assert(is_string($type)); - - return array_map(static fn ($id): mixed => $connection->convertToDatabaseValue($id, $type), $identifiers); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php deleted file mode 100644 index f630ee1..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/RootTypeWalker.php +++ /dev/null @@ -1,48 +0,0 @@ - root entity id type resolution can be cached in the query cache. - */ -final class RootTypeWalker extends SqlWalker -{ - public function walkSelectStatement(AST\SelectStatement $selectStatement): string - { - // Get the root entity and alias from the AST fromClause - $from = $selectStatement->fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Can only process queries that select only one FROM component'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - return PersisterHelper::getTypeOfField( - $identifierFieldName, - $rootClass, - $this->getQuery() - ->getEntityManager(), - )[0]; - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php b/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php deleted file mode 100644 index a0fdd01..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/RowNumberOverFunction.php +++ /dev/null @@ -1,40 +0,0 @@ -walkOrderByClause( - $this->orderByClause, - )) . ')'; - } - - /** - * @throws RowNumberOverFunctionNotEnabled - * - * @inheritdoc - */ - public function parse(Parser $parser): void - { - throw RowNumberOverFunctionNotEnabled::create(); - } -} diff --git a/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php b/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php deleted file mode 100644 index 01741ca..0000000 --- a/vendor/doctrine/orm/src/Tools/Pagination/WhereInWalker.php +++ /dev/null @@ -1,116 +0,0 @@ -fromClause->identificationVariableDeclarations; - - if (count($from) > 1) { - throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction'); - } - - $fromRoot = reset($from); - $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable; - $rootClass = $this->getMetadataForDqlAlias($rootAlias); - $identifierFieldName = $rootClass->getSingleIdentifierFieldName(); - - $pathType = PathExpression::TYPE_STATE_FIELD; - if (isset($rootClass->associationMappings[$identifierFieldName])) { - $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - } - - $pathExpression = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $rootAlias, $identifierFieldName); - $pathExpression->type = $pathType; - - $hasIds = $this->_getQuery()->getHint(self::HINT_PAGINATOR_HAS_IDS); - - if ($hasIds) { - $arithmeticExpression = new ArithmeticExpression(); - $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression( - [$pathExpression], - ); - $expression = new InListExpression( - $arithmeticExpression, - [new InputParameter(':' . self::PAGINATOR_ID_ALIAS)], - ); - } else { - $expression = new NullComparisonExpression($pathExpression); - } - - $conditionalPrimary = new ConditionalPrimary(); - $conditionalPrimary->simpleConditionalExpression = $expression; - if ($selectStatement->whereClause) { - if ($selectStatement->whereClause->conditionalExpression instanceof ConditionalTerm) { - $selectStatement->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary; - } elseif ($selectStatement->whereClause->conditionalExpression instanceof ConditionalPrimary) { - $selectStatement->whereClause->conditionalExpression = new ConditionalExpression( - [ - new ConditionalTerm( - [ - $selectStatement->whereClause->conditionalExpression, - $conditionalPrimary, - ], - ), - ], - ); - } else { - $tmpPrimary = new ConditionalPrimary(); - $tmpPrimary->conditionalExpression = $selectStatement->whereClause->conditionalExpression; - $selectStatement->whereClause->conditionalExpression = new ConditionalTerm( - [ - $tmpPrimary, - $conditionalPrimary, - ], - ); - } - } else { - $selectStatement->whereClause = new WhereClause( - new ConditionalExpression( - [new ConditionalTerm([$conditionalPrimary])], - ), - ); - } - } -} -- cgit v1.2.3