/** * @param string $itemName The property name * @param SearchQueryExpr $value The sub query * @return string */ protected function processSubQueryValue($itemName, SearchQueryExpr $value) { if ($value->isEmpty()) { return ''; } $result = $this->processExpr($value, $itemName); if ($value->isComplex()) { $result = sprintf('(%s)', $result); } return $result; }
/** * Arranges the given search expression before it can be converted to its string representation * As IMAP SEARCH command uses prefixed OR operator in its search expressions we need to prepare * our search expression before it will be converted to a string. * Examples: * 'val1 OR val2' need to be changed to 'OR val1 val2' * 'val1 OR val2 OR val3' need to be changed to 'OR val1 OR val2 val3' * 'NOT val1 OR val2' need to be changed to 'OR NOT val1 val2' * * @param SearchQueryExpr $expr The search expression * @return SearchQueryExpr */ protected function arrangeExpr(SearchQueryExpr $expr) { // Make a clone of the expression and find out OR operators $result = new SearchQueryExpr(); $orOperatorPositions = array(); $i = 0; foreach ($expr as $item) { if ($item instanceof SearchQueryExprOperator) { $result->add($item); if ($item->getName() === 'OR') { $orOperatorPositions[] = $i; } } elseif ($item instanceof SearchQueryExpr) { $result->add($this->arrangeExpr($item)); } else { /** @var SearchQueryExprValueBase $item */ $value = $item->getValue(); if ($value instanceof SearchQueryExpr) { $item->setValue($this->arrangeExpr($value)); } $result->add($item); } $i++; } // Arrange OR operators is any foreach ($orOperatorPositions as $orPos) { $i = $orPos - 1; $parenthesisCounter = 0; while ($i >= 0) { $item = $result[$i]; if ($item instanceof SearchQueryExprOperator) { /** @var SearchQueryExprOperator $item */ switch ($item->getName()) { case '(': $parenthesisCounter--; break; case ')': $parenthesisCounter++; break; } } elseif ($parenthesisCounter === 0) { $this->moveOperator($result, $orPos, $this->correctNewPositionOfOperatorIfNeeded($result, $i)); break; } $i--; } if ($i === -1 && $parenthesisCounter === 0) { $this->moveOperator($result, $orPos, 0); } } return $result; }
/** * {@inheritdoc} */ protected function processSubQueryValue($itemName, SearchQueryExpr $value) { if ($value->isEmpty()) { return ''; } if ($itemName !== null) { $keyword = $this->getKeyword($itemName); if (!$keyword) { throw new \InvalidArgumentException(sprintf('Unsupported property "%s".', $itemName)); } $result = sprintf('%s%s', $keyword, $this->getNameValueDelimiter()); } else { $result = ''; } $expr = $this->processExpr($value); $result .= $value->isComplex() ? sprintf('(%s)', $expr) : $expr; return $result; }
private function andOperatorIfNeeded() { $exprItems = $this->expr->getItems(); $lastIndex = count($exprItems) - 1; if ($lastIndex != -1) { $lastItem = $exprItems[$lastIndex]; if (!$lastItem instanceof SearchQueryExprOperator || $lastItem instanceof SearchQueryExprOperator && $lastItem->getName() == ')') { $this->andOperator(); } } }