private function getQueryField(SearchQueryInterface $query) { $field = null; if ($query instanceof BooleanQueryInterface) { foreach ($query->getSubQueries() as $subQuery) { $subQueryField = $this->getQueryField($subQuery); if ($field && (!$subQueryField || $field !== $subQueryField)) { return false; } if ($subQueryField) { $field = $subQueryField; } } } elseif ($query instanceof FieldQueryInterface) { $field = $query->getField(); } return $field; }
/** * @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; }
/** * 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; }
/** * @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); }
/** * @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; }
/** * Applies full text search settings to query. * * @param SearchQueryInterface $searchQuery * @param AttributeDescriptor[] $fullTextSearchAttributes * @param string $fullTextSearchParam * @return SearchQueryInterface */ public function applyFullTextSearchSettings(SearchQueryInterface $searchQuery, $fullTextSearchAttributes, $fullTextSearchParam = 'text') { if ($fullTextSearchAttributes) { if ($searchQuery instanceof BooleanQueryInterface) { $subQueries = $searchQuery->getSubQueries(); $signs = $searchQuery->getSigns(); foreach ($subQueries as $key => $subQuery) { $subQueries[$key] = $this->applyFullTextSearchSettings($subQuery, $fullTextSearchAttributes, $fullTextSearchParam); } $searchQuery->setSubQueries($subQueries, $signs); } elseif ($searchQuery instanceof Term) { $field = $searchQuery->getField(); if ($field == $fullTextSearchParam) { $fields = array_map(function (AttributeDescriptor $attribute) { return $attribute->name; }, $fullTextSearchAttributes); $searchQuery = new MultiMatch($fields, $searchQuery); } elseif (array_filter($fullTextSearchAttributes, function (AttributeDescriptor $attribute) use($field) { return $attribute->name == $field; })) { $searchQuery = new Match($searchQuery->getField(), $searchQuery); } } } return $searchQuery; }
protected static function removeQueryByFieldName(SearchQueryInterface $fromQuery, $field, $sign = true) { if ($fromQuery instanceof BooleanQueryInterface) { $subQueries = $fromQuery->getSubQueries(); $signs = $fromQuery->getSigns(); $removed = false; foreach ($subQueries as $key => $subQuery) { if ($subQuery instanceof FieldQueryInterface) { if ($signs[$key] === $sign && $subQuery->getField() === $field) { unset($subQueries[$key], $signs[$key]); $removed = true; } } } if (!$removed) { foreach ($subQueries as $key => $subQuery) { if ($subQuery instanceof BooleanQueryInterface) { $subQueries[$key] = self::removeQueryByFieldName($subQuery, $field, $sign); } } } $fromQuery->setSubQueries($subQueries, $signs); } elseif ($fromQuery instanceof FieldQueryInterface && $fromQuery->getField() === $field) { return new Boolean(); } return $fromQuery; }