From 207a2fa5c3440ef4cc266aa539cc26916c8f8f32 Mon Sep 17 00:00:00 2001 From: William Arin Date: Sat, 20 Jul 2024 11:23:28 +0200 Subject: [PATCH 1/2] fix: remove getQueryPart deprecations --- .../Repository/AbstractEntityRepository.php | 57 +++++-------------- src/Bridge/Repository/TermRepository.php | 12 +++- 2 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/Bridge/Repository/AbstractEntityRepository.php b/src/Bridge/Repository/AbstractEntityRepository.php index ae7d2e7..fdefd17 100644 --- a/src/Bridge/Repository/AbstractEntityRepository.php +++ b/src/Bridge/Repository/AbstractEntityRepository.php @@ -142,9 +142,13 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer $prefixedEntityBaseFields = $this->getPrefixedEntityBaseFields('p'); + $hasSelectColumns = array_filter( + $normalizedCriteria, + static fn (mixed $value) => $value instanceof SelectColumns, + ); + $queryBuilder = $this->entityManager->getConnection() ->createQueryBuilder() - ->select(...$prefixedEntityBaseFields) ->from($this->entityManager->getTablesPrefix() . static::TABLE_NAME, 'p') ->addGroupBy(...$prefixedEntityBaseFields) ; @@ -155,7 +159,10 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer ; } - $this->addSelectForExtraFields($queryBuilder); + if (!$hasSelectColumns) { + $queryBuilder->select(...$prefixedEntityBaseFields); + $this->addSelectForExtraFields($queryBuilder); + } foreach ($normalizedCriteria as $field => $value) { if ($this->handleSpecialCriteria($queryBuilder, $criteria, $field, $value) === self::IS_SPECIAL_CRITERIA) { @@ -554,16 +561,11 @@ private function joinSelfMetaTable(QueryBuilder $queryBuilder, bool $incrementIf private function hasJoin(QueryBuilder $queryBuilder, string $joinAlias): bool { - $joinQueryPart = $queryBuilder->getQueryPart('join'); + if (preg_match_all('/JOIN (\w+) (\w+) ON p\./im', $queryBuilder->getSQL(), $matches, PREG_SET_ORDER)) { + return count(array_filter($matches, static fn (array $match) => $match[2] === $joinAlias)) > 0; + } - return array_key_exists('p', $joinQueryPart) - && is_array($joinQueryPart['p']) - && count( - array_filter( - $joinQueryPart['p'], - static fn (array $part) => !empty($part['joinAlias']) && $part['joinAlias'] === $joinAlias, - ) - ) > 0; + return false; } private function createRelationshipCriteria( @@ -809,18 +811,15 @@ private function getPrefixedCriteriaForPostRelationshipCondition( private function selectColumns(QueryBuilder $queryBuilder, array $extraFields, SelectColumns $value): void { $selects = []; - $hasExtraFields = false; - $queryBuilder->resetQueryPart('groupBy'); + $queryBuilder->resetGroupBy(); foreach ($value->getColumns() as $column) { if (in_array($column, $extraFields, true)) { $mappedMetaKey = $this->getMappedMetaKey($column); $selects[] = select_from_eav($column, $mappedMetaKey); - $hasExtraFields = true; } elseif (str_starts_with($column, 'MAX(')) { $selects[] = $column; - $hasExtraFields = true; $this->joinSelfMetaTable($queryBuilder); } else { foreach ($this->tableAliases as $alias => $fields) { @@ -836,33 +835,5 @@ private function selectColumns(QueryBuilder $queryBuilder, array $extraFields, S $queryBuilder->select(...$selects, ...$this->additionalFieldsToSelect); $this->additionalFieldsToSelect = []; - - if (!$hasExtraFields) { - $joinQueryPart = $queryBuilder->getQueryPart('join'); - - if (empty($joinQueryPart)) { - return; - } - - $queryBuilder->resetQueryPart('join'); - - foreach ($joinQueryPart['p'] as $index => $part) { - if ($part['joinAlias'] === 'pm_self') { - unset($joinQueryPart['p'][$index]); - } - } - - foreach ($joinQueryPart as $alias => $parts) { - foreach ($parts as $part) { - $method = match ($part['joinType']) { - 'left' => 'leftJoin', - 'right' => 'rightJoin', - default => 'join', - }; - - $queryBuilder->{$method}($alias, $part['joinTable'], $part['joinAlias'], $part['joinCondition']); - } - } - } } } diff --git a/src/Bridge/Repository/TermRepository.php b/src/Bridge/Repository/TermRepository.php index de0c993..5fc18fa 100644 --- a/src/Bridge/Repository/TermRepository.php +++ b/src/Bridge/Repository/TermRepository.php @@ -38,9 +38,15 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer ->addGroupBy('tt.taxonomy') ; + preg_match('/SELECT (.*) FROM/im', $queryBuilder->getSQL(), $match); + $selectedFields = explode(', ', $match[1] ?? ''); + + preg_match('/GROUP BY (.*)\s?(?:HAVING|ORDER|LIMIT|OFFSET|FETCH|$)/im', $queryBuilder->getSQL(), $match); + $groupByFields = explode(', ', $match[1] ?? ''); + if (\count(array_filter($criteria, static fn ($condition) => $condition instanceof SelectColumns)) === 0) { $extraFields = array_diff( - $queryBuilder->getQueryPart('select'), + $selectedFields, $this->getPrefixedFields(['term_id', 'name', 'slug', 'taxonomy', 'term_taxonomy_id', 'count']), ); @@ -49,8 +55,8 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer ...$extraFields, ]); } else { - foreach ($this->getPrefixedFields($queryBuilder->getQueryPart('select')) as $field) { - if (!\in_array($field, $queryBuilder->getQueryPart('groupBy'), true)) { + foreach ($this->getPrefixedFields($selectedFields) as $field) { + if (!\in_array($field, $groupByFields, true)) { $queryBuilder->addGroupBy($field); } } From 8ec272de8c24822cc8349cdedf7cad4b2f54f250 Mon Sep 17 00:00:00 2001 From: William Arin Date: Thu, 25 Jul 2024 00:03:37 +0200 Subject: [PATCH 2/2] feat: dbal 4.0 compatibility --- composer.json | 2 +- .../Repository/AbstractEntityRepository.php | 15 +++++++++++---- src/Bridge/Repository/TermRepository.php | 14 ++++++++------ test/Test/TestCase.php | 6 +++++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index b9ef566..b8e4c91 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": ">=8.0", "doctrine/annotations": "^2.0", - "doctrine/dbal": "^3.3", + "doctrine/dbal": "^3.8 || ^4.0", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.27", "symfony/config": "^6.0 || ^7.0", diff --git a/src/Bridge/Repository/AbstractEntityRepository.php b/src/Bridge/Repository/AbstractEntityRepository.php index fdefd17..caecaf1 100644 --- a/src/Bridge/Repository/AbstractEntityRepository.php +++ b/src/Bridge/Repository/AbstractEntityRepository.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Query\Expression\CompositeExpression; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Query\QueryException; use JetBrains\PhpStorm\ArrayShape; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; @@ -174,8 +175,10 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer $this->addOrderByClause($queryBuilder, $orderBy); - $queryBuilder->addSelect(...$this->additionalFieldsToSelect); - $this->additionalFieldsToSelect = []; + if (!empty($this->additionalFieldsToSelect)) { + $queryBuilder->addSelect(...$this->additionalFieldsToSelect); + $this->additionalFieldsToSelect = []; + } return $queryBuilder; } @@ -561,8 +564,12 @@ private function joinSelfMetaTable(QueryBuilder $queryBuilder, bool $incrementIf private function hasJoin(QueryBuilder $queryBuilder, string $joinAlias): bool { - if (preg_match_all('/JOIN (\w+) (\w+) ON p\./im', $queryBuilder->getSQL(), $matches, PREG_SET_ORDER)) { - return count(array_filter($matches, static fn (array $match) => $match[2] === $joinAlias)) > 0; + try { + if (preg_match_all('/JOIN (\w+) (\w+) ON p\./im', $queryBuilder->getSQL(), $matches, PREG_SET_ORDER)) { + return count(array_filter($matches, static fn (array $match) => $match[2] === $joinAlias)) > 0; + } + } catch (QueryException) { + return false; } return false; diff --git a/src/Bridge/Repository/TermRepository.php b/src/Bridge/Repository/TermRepository.php index 5fc18fa..9a547b1 100644 --- a/src/Bridge/Repository/TermRepository.php +++ b/src/Bridge/Repository/TermRepository.php @@ -50,10 +50,10 @@ public function createFindByQueryBuilder(array $criteria, ?array $orderBy): Quer $this->getPrefixedFields(['term_id', 'name', 'slug', 'taxonomy', 'term_taxonomy_id', 'count']), ); - $queryBuilder->select([ + $queryBuilder->select( ...$this->getPrefixedFields(['term_id', 'name', 'slug', 'taxonomy', 'term_taxonomy_id', 'count']), - ...$extraFields, - ]); + ...$extraFields + ); } else { foreach ($this->getPrefixedFields($selectedFields) as $field) { if (!\in_array($field, $groupByFields, true)) { @@ -152,19 +152,21 @@ public function removeTermsFromEntity(BaseEntity $entity, array $terms): void private function recountTerms(): void { + $tableName = $this->entityManager->getTablesPrefix() . 'term_taxonomy'; + $subSelect = $this->entityManager->getConnection() ->createQueryBuilder() ->select('COUNT(*)') ->from($this->entityManager->getTablesPrefix() . 'term_relationships', 'tr') ->leftJoin('tr', $this->entityManager->getTablesPrefix() . 'posts', 'p', 'p.id = tr.object_id') - ->where('tr.term_taxonomy_id = tt.term_taxonomy_id') - ->andWhere("tt.taxonomy NOT IN ('link_category')") + ->where("tr.term_taxonomy_id = $tableName.term_taxonomy_id") + ->andWhere("$tableName.taxonomy NOT IN ('link_category')") ->andWhere("p.post_status IN ('publish', 'future')") ; $this->entityManager->getConnection() ->createQueryBuilder() - ->update($this->entityManager->getTablesPrefix() . 'term_taxonomy', 'tt') + ->update($tableName) ->set('count', sprintf('(%s)', $subSelect->getSQL())) ->executeStatement() ; diff --git a/test/Test/TestCase.php b/test/Test/TestCase.php index 279c3cc..1fa503a 100644 --- a/test/Test/TestCase.php +++ b/test/Test/TestCase.php @@ -7,6 +7,7 @@ use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Tools\DsnParser; use PHPUnit\Framework\TestCase as BaseTestCase; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; @@ -39,7 +40,10 @@ abstract class TestCase extends BaseTestCase protected function setUp(): void { - $this->connection = DriverManager::getConnection(['url' => getenv('WORDPRESS_DATABASE_URL')]); + $dsnParser = new DsnParser(['mysql' => 'pdo_mysql']); + $this->connection = DriverManager::getConnection( + $dsnParser->parse(getenv('WORDPRESS_DATABASE_URL')) + ); $loader = class_exists('\\Symfony\\Component\\Serializer\\Mapping\\Loader\\AnnotationLoader') ? new AnnotationLoader(new AnnotationReader())