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