' AND ', self::EXPR_OR => ' OR ', self::EXPR_HAVING => ' HAVING ', self::EXPR_LIKE => ' LIKE ', self::EXPR_IN => ' IN ', self::EXPR_BETWEEN => ' BETWEEN ', self::EXPR_NOT_IN => ' NOT IN ', ); /** @var array */ protected $expression = array( 'base' => null, // this can be a string or a QueryBuilderExpression 'and' => array(), 'or' => array(), ); /** * @param null $expression */ public function __construct(QueryBuilder $qb, $expression = null) { $this->qb = $qb; $this->expression['base'] = $expression; } /** * @return string * @throws Exception */ public function __toString() { return $this->build(); } /** * addOr * * Add and OR caluse as a string, QueryBuilderExpression, or array of either. * * @param string|array[string|QueryBuilderExpression] $expr * @return $this */ public function orX($expression) { $args = func_get_args(); foreach ($args as $expr) { $this->expression['or'][] = $expr; } return $this; } /** * addAnd * * Add and AND caluse as a string, QueryBuilderExpression, or array of either. * * @param string|array[string|QueryBuilderExpression] $expr * @return $this */ public function andX($expression) { $args = func_get_args(); foreach ($args as $expr) { $this->expression['and'][] = $expr; } return $this; } /** * in * * Alias of andIn * @param string $field * @param array $values * @param $type * * @return $this; */ public function in($field, array $values, $type = QueryBuilder::PARAMETER_INT) { return $this->andIn($field, $values, $type); } /** * andIn * * Checks if a field is contained in a set of values * * @param string $field * @param array $values * @param $type * * @return $this; */ public function andIn($field, array $values, $type = QueryBuilder::PARAMETER_INT) { $values = array_values($values); // realign keys if needed $placeholders = array(); foreach ($values as $k => $v) { $placeholder = $this->qb->createPlaceholderName(sprintf('%s_in_%d', $field, $k)); $placeholders[] = $placeholder; $this->qb->setParameter($placeholder, $v); } $this->expression['and'][] = sprintf('%s %s (:%s)', $field, $this->words[static::EXPR_IN], implode(',:', $placeholders)); return $this; } /** * orIn * * Checks if a field is contained in a set of values * * @param string $field * @param array $values * @param $type * * @return $this */ public function orIn($field, array $values, $type = QueryBuilder::PARAMETER_INT) { $values = array_values($values); // realign keys if needed $placeholders = array(); foreach ($values as $k => $v) { $placeholder = $this->qb->createPlaceholderName(sprintf('%s_in_%d', $field, $k)); $placeholders[] = $placeholder; $this->qb->setParameter($placeholder, $v); } $this->expression['or'][] = sprintf('%s %s (:%s)', $field, $this->words[static::EXPR_IN], implode(',:', $placeholders)); return $this; } /** * notIn * * Alias of andNotIn * * @param string $field * @param array $values * @param $type * * @return $this; */ public function notIn($field, array $values, $type = QueryBuilder::PARAMETER_INT) { return $this->andNotIn($field, $values, $type); } /** * andNotIn * * Excludes where a field is in a given set of values * * @param string $field * @param array $values * @param $type * * @return $this; */ public function andNotIn($field, array $values, $type = QueryBuilder::PARAMETER_INT) { $values = array_values($values); // realign keys if needed $placeholders = array(); foreach ($values as $k => $v) { $placeholder = $this->qb->createPlaceholderName(sprintf('%s_not_in_%d', $field, $k)); $placeholders[] = $placeholder; $this->qb->setParameter($placeholder, $v); } $this->expression['and'][] = sprintf('%s %s (:%s)', $field, $this->words[static::EXPR_NOT_IN], implode(',:', $placeholders)); return $this; } /** * orNotIn * * Excludes where a field is in a given set of values * * @param string $field * @param array $values * @param $type * * @return $this */ public function orNotIn($field, array $values, $type = QueryBuilder::PARAMETER_INT) { $values = array_values($values); // realign keys if needed $placeholders = array(); foreach ($values as $k => $v) { $placeholder = $this->qb->createPlaceholderName(sprintf('%s_not_in_%d', $field, $k)); $placeholders[] = $placeholder; $this->qb->setParameter($placeholder, $v); } $this->expression['or'][] = sprintf('%s %s (:%s)', $field, $this->words[static::EXPR_NOT_IN], implode(',:', $placeholders)); return $this; } /** * between * * @param string $field * @param string|DateTime $from * @param string|DateTime $to * * @return $this */ public function between($field, $from, $to) { return $this->andBetween($field, $from, $to); } /** * andBetween * * @param string $field * @param string|DateTime $from * @param string|DateTime $to * * @return $this */ public function andBetween($field, $from, $to) { $fromParameter = $this->qb->createPlaceholderName($field.'_from'); $toParameter = $this->qb->createPlaceholderName($field.'_to'); if ($from instanceof \DateTime) { $from = $from->format('Y-m-d H:i:s'); } if ($to instanceof \DateTime) { $to = $to->format('Y-m-d H:i:s'); } $this->expression['and'][] = sprintf('%s %s :%s %s :%s', $field, $this->words[static::EXPR_BETWEEN], $fromParameter, $this->words[static::EXPR_AND], $toParameter ); $this->qb->setParameter($fromParameter, $from); $this->qb->setParameter($toParameter, $to); return $this; } /** * orBetween * * @param string $field * @param string|DateTime $from * @param string|DateTime $to * * @return $this */ public function orBetween($field, $from, $to) { $fromParameter = $this->qb->createPlaceholderName($field.'_from'); $toParameter = $this->qb->createPlaceholderName($field.'_to'); if ($from instanceof \DateTime) { $from = $from->format('Y-m-d H:i:s'); } if ($to instanceof \DateTime) { $to = $to->format('Y-m-d H:i:s'); } $this->expression['or'][] = sprintf('%s %s :%s %s :%s', $field, $this->words[static::EXPR_BETWEEN], $fromParameter, $this->words[static::EXPR_AND], $toParameter ); $this->qb->setParameter($fromParameter, $from); $this->qb->setParameter($toParameter, $to); return $this; } /** * build * * @return string */ public function build() { $return = null; $isExpression = $this->expression['base'] instanceof QueryBuilderExpression; $isNested = count($this->expression['and']) || count($this->expression['or']); if (empty($this->expression['base']) && !$isNested) { throw new \InvalidArgumentException(sprintf('Expression does not contain a valid expression')); } if (!$isNested && !$isExpression) { return $this->expression['base']; } if ($isNested) { $return .= static::GROUP_LEFT; } if ($this->expression['base']) { if ($this->expression['base'] instanceof QueryBuilderExpression) { $return .= $this->expression['base']->build(); } else if (is_array($this->expression['base'])) { throw new \Exception('Expression is array'); } else { if ($isNested) { $return .= static::GROUP_LEFT . $this->expression['base'] . static::GROUP_RIGHT; } else { $return .= $this->expression['base']; } } } if ($this->expression['base'] && count($this->expression['and'])) { $return .= $this->words[static::EXPR_AND]; } if (count($this->expression['and'])) { if ($isNested) { $return .= static::GROUP_LEFT; } $return .= implode($this->words[static::EXPR_AND], $this->expression['and']); if ($isNested) { $return .= static::GROUP_RIGHT; } } if (count($this->expression['and']) && count($this->expression['or']) == 1) { $return .= $this->words[static::EXPR_OR]; } if (count($this->expression['or'])) { if ($isNested) { $return .= static::GROUP_LEFT; } $return .= implode($this->words[static::EXPR_OR], $this->expression['or']); if ($isNested) { $return .= static::GROUP_RIGHT; } } if ($isNested) { $return .= static::GROUP_RIGHT; } return $return; } } ?>