Skip to content

Commit

Permalink
fix: multiple EAV conditions now give correct result
Browse files Browse the repository at this point in the history
  • Loading branch information
williarin committed Aug 3, 2022
1 parent 3903478 commit 3e7e7cc
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 32 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ services:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=wp_test
- MYSQL_ROOT_HOST=%
command: --default-authentication-plugin=mysql_native_password
command: --default-authentication-plugin=mysql_native_password --max_connections=10000

wordpress:
image: wordpress:fpm-alpine
Expand Down
83 changes: 52 additions & 31 deletions src/Bridge/Repository/AbstractEntityRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,30 +409,29 @@ protected function handleRegularCriteria(
true,
)
) {
$metaAlias = sprintf('pm_%s', $aliasNumber ?? 'self');

if ($aliasNumber === null) {
$this->joinSelfMetaTable($queryBuilder);
$metaAlias = $this->joinSelfMetaTable($queryBuilder, true);
$this->tableAliases[$metaAlias][] = $field;
}

if ($this->isFieldMapped($field, $entityClassName)) {
$exprKey = sprintf('pm_%s.meta_key = :%s_key', $aliasNumber ?? 'self', $snakeField);
$exprKey = sprintf('%s.meta_key = :%s_key', $metaAlias, $snakeField);
$queryBuilder->andWhere($exprKey)
->setParameter(
sprintf('%s_key', $snakeField),
$this->getMappedMetaKey($field, $entityClassName),
)
;
} else {
$exprKey = sprintf(
'TRIM(LEADING \'_\' FROM pm_%s.meta_key) = :%s_key',
$aliasNumber ?? 'self',
$snakeField,
);
$exprKey = sprintf("TRIM(LEADING '_' FROM %s.meta_key) = :%s_key", $metaAlias, $snakeField);
$queryBuilder->andWhere($exprKey)
->setParameter(sprintf('%s_key', $snakeField), $field)
;
}

$exprValue = sprintf('pm_%s.meta_value %s %s', $aliasNumber ?? 'self', $operator, $parameter);
$exprValue = sprintf('%s.meta_value %s %s', $metaAlias, $operator, $parameter);
$queryBuilder->andWhere($exprValue);
} else {
if ($operator === Operand::OPERATOR_IN_ALL) {
Expand Down Expand Up @@ -461,31 +460,52 @@ protected function addOrderByClause(QueryBuilder $queryBuilder, ?array $orderBy)
}
}

private function joinSelfMetaTable(QueryBuilder $queryBuilder): void
private function joinSelfMetaTable(QueryBuilder $queryBuilder, bool $incrementIfNecessary = false): string
{
if (!array_key_exists('pm_self', $this->tableAliases)) {
$this->tableAliases['pm_self'] = [];
$applyJoin = function (QueryBuilder $queryBuilder, string $alias): void {
if (!array_key_exists($alias, $this->tableAliases)) {
$this->tableAliases[$alias] = [];
}

$queryBuilder->leftJoin(
'p',
$this->entityManager->getTablesPrefix() . static::TABLE_META_NAME,
$alias,
sprintf('p.%s = %s.%s', static::TABLE_IDENTIFIER, $alias, static::TABLE_META_IDENTIFIER),
);
};

static $aliasNumber = 1;
$alias = 'pm_self';

if (!$incrementIfNecessary && $this->hasJoin($queryBuilder, $alias)) {
return $alias;
}

$joinQueryPart = $queryBuilder->getQueryPart('join');
if (!$this->hasJoin($queryBuilder, $alias)) {
$applyJoin($queryBuilder, $alias);

if (
array_key_exists('p', $joinQueryPart)
&& is_array($joinQueryPart['p'])
&& count(array_filter(
$joinQueryPart['p'],
static fn (array $part) => !empty($part['joinAlias']) && $part['joinAlias'] === 'pm_self',
)) > 0
) {
return;
return $alias;
}

$queryBuilder->leftJoin(
'p',
$this->entityManager->getTablesPrefix() . static::TABLE_META_NAME,
'pm_self',
sprintf('p.%s = pm_self.%s', static::TABLE_IDENTIFIER, static::TABLE_META_IDENTIFIER),
);
$alias .= '_' . $aliasNumber++;
$applyJoin($queryBuilder, $alias);

return $alias;
}

private function hasJoin(QueryBuilder $queryBuilder, string $joinAlias): bool
{
$joinQueryPart = $queryBuilder->getQueryPart('join');

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;
}

private function createRelationshipCriteria(
Expand Down Expand Up @@ -540,10 +560,11 @@ private function createRelationshipCriteria(

$this->addEntityExtraField($trimmedAlias);
$this->additionalFieldsToSelect[] = sprintf(
"MAX(CASE WHEN %s.meta_key = '%s' THEN %s.post_id END) AS `%s`",
"MAX(CASE WHEN %s.meta_key = '%s' THEN %s.%s END) AS `%s`",
$alias,
$condition->getRelationshipFieldName(),
$alias,
self::TABLE_META_IDENTIFIER,
$trimmedAlias,
);
}
Expand All @@ -567,7 +588,7 @@ private function createTermRelationshipCriteria(
$tableAlias,
$parameterName,
$tableAlias,
str_contains($tableAlias, 'relation') ? 'post_id' : 'meta_value',
str_contains($tableAlias, 'relation') ? self::TABLE_META_IDENTIFIER : 'meta_value',
$aliasNumber,
);
$queryBuilder->setParameter($parameterName, $mappedKey);
Expand Down Expand Up @@ -676,9 +697,9 @@ private function addPostMetaJoinForPostRelationshipCondition(

$queryBuilder->leftJoin(
sprintf('p_%d', $aliasNumber),
$this->entityManager->getTablesPrefix() . 'postmeta',
$this->entityManager->getTablesPrefix() . self::TABLE_META_NAME,
$alias,
sprintf('p_%d.id = pm_%d.post_id', $aliasNumber, $aliasNumber),
sprintf('p_%d.id = pm_%d.%s', $aliasNumber, $aliasNumber, self::TABLE_META_IDENTIFIER),
);

foreach ($extraFields as $extraField) {
Expand Down
10 changes: 10 additions & 0 deletions test/Test/Bridge/Repository/ProductRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ public function testFindByEAVRegexp(): void
self::assertEquals([16, 23], array_column($products, 'id'));
}

public function testFindByMultipleEAVConditions(): void
{
$products = $this->repository->findBy([
'sku' => new Operand('hoodie.*logo|zipper', Operand::OPERATOR_REGEXP),
'thumbnail_id' => 52,
]);

self::assertEquals([23], array_column($products, 'id'));
}

public function testFindByCriteriaOr(): void
{
$products = $this->repository->findBy([
Expand Down

0 comments on commit 3e7e7cc

Please sign in to comment.