protected function queryToString(SearchQueryInterface $query, $asValue = false, $topLevelQuery = true) { $queryString = ''; if ($query instanceof BooleanQueryInterface) { $subQueries = $query->getSubQueries(); $groupedQueries = []; $operator1 = $this->getOperator(reset($query->getSigns()), $topLevelQuery); foreach ($subQueries as $subQuery) { if ($field = $this->getQueryField($subQuery)) { $groupedQueries[$field][] = $subQuery; } else { $groupedQueries[] = $subQuery; } } $queryStringParts = []; foreach ($groupedQueries as $field => $queries) { $operator2 = $this->getOperator(reset($query->getSigns()), is_string($field) ? false : $topLevelQuery); if (!is_array($queries)) { $queries = [$queries]; } $queryParts = []; foreach ($queries as $queryItem) { $topLevelQuery = $queryItem instanceof BooleanQueryInterface ? $topLevelQuery : false; $queryParts[] = $this->queryToString($queryItem, is_string($field), $topLevelQuery); } $queryStringParts[] = (!$asValue && is_string($field) ? $field . $this->syntax[self::SYNTAX_EQUAL_OPERATOR] : '') . implode($operator2, $queryParts); } $queryString = implode($operator1, $queryStringParts); } elseif ($query instanceof FieldQueryInterface) { if ($query instanceof RangeInterface) { $queryString = $query->isIncludeLowerBound() ? $this->syntax[self::SYNTAX_INCLUDED_RANGE_START] : $this->syntax[self::SYNTAX_EXCLUDED_RANGE_START]; $queryString .= $query->getLowerBound() !== null ? $query->getLowerBound() : ''; $queryString .= $this->syntax[self::SYNTAX_RANGE_TO_TERM]; $queryString .= $query->getUpperBound() !== null ? $query->getUpperBound() : ''; $queryString .= $query->isIncludeUpperBound() ? $this->syntax[self::SYNTAX_INCLUDED_RANGE_END] : $this->syntax[self::SYNTAX_EXCLUDED_RANGE_END]; } elseif ($query instanceof Term) { $queryString = $query->getTerm(); } elseif ($query instanceof Match || $query instanceof MultiMatch) { $queryString = $query->getTerm()->getTerm(); } if ($queryString !== '' && !$asValue) { $queryString = $query->getField() . $this->syntax[self::SYNTAX_EQUAL_OPERATOR] . $queryString; } } return $queryString; }
/** * @param SearchQueryInterface $query * @return array */ protected function mapQuery(SearchQueryInterface $query) { $queryArr = []; if ($query instanceof Boolean) { $signs = $query->getSigns(); $boolean = []; foreach ($query->getSubQueries() as $key => $subQuery) { $sign = isset($signs[$key]) ? $signs[$key] : null; switch ($sign) { case true: if ($subQueryArr = $this->mapQuery($subQuery)) { if (!isset($boolean['must'])) { $boolean['must'] = []; } $boolean['must'][] = $this->mapQuery($subQuery); } break; case false: if ($subQueryArr = $this->mapQuery($subQuery)) { if (!isset($booleanr['must_not'])) { $boolean['must_not'] = []; } $boolean['must_not'][] = $this->mapQuery($subQuery); } break; case null: if ($subQueryArr = $this->mapQuery($subQuery)) { if (!isset($boolean['should'])) { $boolean['should'] = []; } $boolean['should'][] = $this->mapQuery($subQuery); } break; } } if ($boolean) { $queryArr['bool'] = $boolean; } } elseif ($query instanceof Term) { $queryArr['term'] = [$query->getField() => $query->getTerm()]; } elseif ($query instanceof Range) { $range = []; if (($from = $query->getLowerBound()) !== null) { $range[$query->isIncludeLowerBound() ? 'gte' : 'gt'] = $from; } if (($to = $query->getUpperBound()) !== null) { $range[$query->isIncludeUpperBound() ? 'lte' : 'lt'] = $to; } $queryArr['range'] = [$query->getField() => $range]; } return $queryArr; }
/** * @inheritdoc */ public function equals(SearchQueryInterface $query) { $sameField = $query instanceof Range && $this->getField() === $query->getField(); return $sameField && ($this->getLowerBound() === $query->getLowerBound() && $this->getUpperBound() === $query->getUpperBound() && $this->isIncludeLowerBound() === $query->isIncludeLowerBound() && $this->isIncludeUpperBound() === $query->isIncludeUpperBound()) ? 1 : ($sameField ? 0 : -1); }
/** * Returns condition by search query. * * @param SearchQueryInterface $query * @return array */ protected function getCondition(SearchQueryInterface $query) { $condition = []; /** @var ActiveRecord $modelClass */ $modelClass = $this->modelClass; $table = $modelClass::tableName(); if ($query instanceof Boolean) { $operator = reset($query->getSigns()) === null ? 'or' : 'and'; $condition = [$operator]; foreach ($query->getSubQueries() as $subQuery) { $condition[] = $this->getCondition($subQuery); } } elseif ($query instanceof Term) { $field = $table . '.' . $query->getField(); $childName = ''; if (($pos = strrpos($query->getField(), '.')) !== false) { $childName = substr($query->getField(), $pos + 1); $name = substr($query->getField(), 0, $pos); } else { $name = $query->getField(); } $attribute = $this->getSearchableAttribute($name); if ($attribute->value and $attribute->value instanceof \Closure) { $attributeValue = call_user_func_array($attribute->value, [new $this->modelClass()]); if ($attributeValue instanceof ActiveQuery) { $modelClass = $attributeValue->modelClass; $relationTable = $modelClass::tableName(); if (!isset($this->_joined[$attribute->name])) { $this->joinWith($attribute->name, false); $this->_joined[$attribute->name] = true; } $field = $relationTable . '.' . ($childName ?: $name); } } $value = $query->getTerm(); $condition = is_array($value) ? ['in', $field, $value] : [$field => $value]; } elseif ($query instanceof Range) { if (($from = $query->getLowerBound()) !== null) { $condition[] = [$query->isIncludeLowerBound() ? '>=' : '>', $table . '.' . $query->getField(), $from]; } if (($to = $query->getUpperBound()) !== null) { $condition[] = [$query->isIncludeLowerBound() ? '<=' : '<', $table . '.' . $query->getField(), $to]; } if ($condition) { $condition = count($condition) == 1 ? $condition[0] : array_merge(['and'], $condition); } } return $condition; }
/** * @param SearchQueryInterface $query * @param bool $asFilter * @return array */ protected function mapQuery(SearchQueryInterface $query, $asFilter = false) { $queryArr = []; if ($query instanceof Boolean) { $signs = $query->getSigns(); $boolean = []; foreach ($query->getSubQueries() as $key => $subQuery) { $sign = isset($signs[$key]) ? $signs[$key] : null; if ($sign === true) { if ($subQueryArr = $this->mapQuery($subQuery, $asFilter)) { if (!isset($boolean['must'])) { $boolean['must'] = []; } $boolean['must'][] = $this->mapQuery($subQuery, $asFilter); } } elseif ($sign === false) { if ($subQueryArr = $this->mapQuery($subQuery, $asFilter)) { if (!isset($booleanr['must_not'])) { $boolean['must_not'] = []; } $boolean['must_not'][] = $this->mapQuery($subQuery, $asFilter); } } elseif ($sign === null) { if ($subQueryArr = $this->mapQuery($subQuery, $asFilter)) { if (!isset($boolean['should'])) { $boolean['should'] = []; } $boolean['should'][] = $this->mapQuery($subQuery, $asFilter); } } } if ($boolean) { $queryArr['bool'] = $boolean; } } elseif ($query instanceof Term) { $queryArr['term'] = [$query->getField() => $query->getTerm()]; } elseif ($query instanceof Range) { $range = []; if (($from = $query->getLowerBound()) !== null) { $range[$query->isIncludeLowerBound() ? 'gte' : 'gt'] = $from; } if (($to = $query->getUpperBound()) !== null) { $range[$query->isIncludeUpperBound() ? 'lte' : 'lt'] = $to; } $queryArr['range'] = [$query->getField() => $range]; } elseif ($query instanceof Match) { $matchQuery = [$query->getField() => $query->getTerm()->getTerm()]; if ($asFilter) { $queryArr['query']['match'] = $matchQuery; } else { $queryArr['match'] = $matchQuery; } } elseif ($query instanceof MultiMatch) { $multiMatchQuery = ['query' => $query->getTerm()->getTerm(), 'type' => 'most_fields', 'fields' => array_values($query->getFields()), 'minimum_should_match' => '75%']; if ($asFilter) { $queryArr['query']['multi_match'] = $multiMatchQuery; } else { $queryArr['multi_match'] = $multiMatchQuery; } } return $queryArr; }