/** * Returns query from context. * * @throws QueryParserException * @return SearchQueryInterface */ public function getQuery() { /** * We treat each level of an expression as a boolean expression in * a Disjunctive Normal Form * * AND operator has higher precedence than OR * * Thus logical query is a disjunction of one or more conjunctions of * one or more query entries */ $expressionParser = new BooleanExpressionParser($this->_defaultLogicalOperator, $this->_higherPriorityLogicalOperator); try { foreach ($this->_entries as $entry) { if ($entry instanceof QueryEntryInterface) { $expressionParser->processLiteral($entry); } else { switch ($entry) { case QueryToken::TYPE_AND_OPERATOR: $expressionParser->processOperator(BooleanExpressionParser::IN_AND_OPERATOR); break; case QueryToken::TYPE_OR_OPERATOR: $expressionParser->processOperator(BooleanExpressionParser::IN_OR_OPERATOR); break; case QueryToken::TYPE_NOT_OPERATOR: $expressionParser->processOperator(BooleanExpressionParser::IN_NOT_OPERATOR); break; default: throw new \UnexpectedValueException('Boolean expression error. Unknown operator type.'); } } } $conjunctions = $expressionParser->finishExpression(); } catch (\Exception $e) { // It's query syntax error message and it should be user friendly. So FSM message is omitted throw new QueryParserException('Boolean expression error.', 0, $e); } // Remove 'only negative' conjunctions foreach ($conjunctions as $conjunctionId => $conjunction) { $nonNegativeEntryFound = false; foreach ($conjunction as $conjunctionEntry) { if ($conjunctionEntry[1] || $conjunctionEntry[1] === null) { $nonNegativeEntryFound = true; break; } } if (!$nonNegativeEntryFound) { unset($conjunctions[$conjunctionId]); } } $subQueries = []; $signs = []; foreach ($conjunctions as $conjunction) { // Check, if it's a one term conjunction if (count($conjunction) === 1) { /** @var QueryEntryInterface $entry */ $entry = $conjunction[0][0]; $subQueries[] = $entry->getQuery(); $signs[end(array_keys($subQueries))] = $conjunction[0][1]; } else { $subQuery = new Boolean(); foreach ($conjunction as $conjunctionEntry) { $entry = $conjunctionEntry[0]; $subQuery->addSubquery($entry->getQuery(), $conjunctionEntry[1]); } $subQueries[] = $subQuery; } } if (count($subQueries) == 1) { return $subQueries[0]; } $query = new Boolean(); foreach ($subQueries as $key => $subQuery) { $query->addSubquery($subQuery, array_key_exists($key, $signs) ? $signs[$key] : ($this->_higherPriorityLogicalOperator === QueryParser::OPERATOR_OR ? true : null)); } return $query; }
/** * Add one query to another. * * @param SearchQueryInterface $toQuery * @param FieldQueryInterface $query * @param bool|null $sign * @return bool|SearchQueryInterface */ protected static function addQuery(SearchQueryInterface $toQuery, FieldQueryInterface $query, $sign = true) { if ($toQuery instanceof BooleanQueryInterface) { $subQueries = $toQuery->getSubQueries(); $signs = $toQuery->getSigns(); foreach ($subQueries as $key => $subQuery) { if ($newQuery = self::addQuery($subQuery, $query, $sign)) { $subQueries[$key] = $newQuery; $toQuery->setSubQueries($subQueries, $signs); return $toQuery; } } } elseif ($toQuery instanceof FieldQueryInterface) { $equal = $toQuery->equals($query); if ($equal === 0) { $newQuery = new Boolean(); $newQuery->setSubQueries([$toQuery, $query], [$sign, $sign]); return $newQuery; } elseif ($equal === 1) { return $toQuery; } } return false; }