* @package Mammut\DB\Sql */ class Select extends Query { use Selective; use Targetable; use Limitable; use Orderable; const SELECT = 'select'; const QUANTIFIER = 'quantifier'; const JOINS = 'joins'; const GROUP = 'group'; const HAVING = 'having'; const OFFSET = 'offset'; const QUANTIFIER_DISTINCT = 'DISTINCT'; const QUANTIFIER_ALL = 'ALL'; const JOIN_INNER = 'inner'; const JOIN_OUTER = 'outer'; const JOIN_LEFT = 'left'; const JOIN_RIGHT = 'right'; const SQL_STAR = '*'; const ORDER_ASCENDING = 'ASC'; const ORDER_DESCENDING = 'DESC'; const COMBINE = 'combine'; const COMBINE_UNION = 'union'; const COMBINE_UNIONALL = 'unionall'; const COMBINE_EXCEPT = 'except'; const COMBINE_INTERSECT = 'intersect'; protected $prefixColumnsWithTable = true; protected $joins = array(); protected $group = null; protected $having = null; protected $combine = false; /** * Creates a new SELECT query model * * @param $table mixed * the base table for the query */ public function __construct($table = null) { if($table) $this->from($table); $this->where = new Where(); $this->having = new Having(); } /** * Short version of quantifier(self::QUANTIFIER_DISTINCT) * * @return $this */ public function distinct() { return $this->quantifier(self::QUANTIFIER_DISTINCT); } /** * Defines a query quantifier * * @param string|iExpression $quantifier * DISTINCT|ALL * @return $this */ public function quantifier($quantifier) { if(!(is_string($quantifier) || $quantifier instanceof iExpression)) throw new \InvalidArgumentException('Quantifier must be one of DISTINCT, ALL, or some platform specific iExpression object'); $this->setup[self::QUANTIFIER] = $quantifier; return $this; } /** * Specify columns from which to select * * Possible valid states: * * array(*) * * array(value, ...) * value can be strings or Expression objects * * array(string => value, ...) * key string will be use as alias, * value can be string or Expression objects * * @param array $columns * @param bool $prefixColumnsWithTable * @return $this */ public function columns(array $columns, $prefixColumnsWithTable = true) { $this->prefixColumnsWithTable = (bool) $prefixColumnsWithTable; foreach($columns as &$c) { if(is_string($c) || is_array($c)) $c = new Literal($c, Literal::TYPE_IDENTIFIER); } $this->setup[self::COLUMNS] = $columns; return $this; } /** * Create join clause * * @param string|array|Table $name * the table to join * @param string $on * the join conditions * @param string $type * one of the JOIN_* constants * @throws \InvalidArgumentException * @return $this */ public function join($name, $on, $type = self::JOIN_INNER) { if($name instanceof Table || (is_array($name) && (!is_string(key($name)) || count($name) !== 1))) throw new \InvalidArgumentException(sprintf("join() expects '%s' as an array is a single element associative array", array_shift($name))); $alias = false; if (is_string($name)) $tbl = new Table($name); elseif ($name instanceof Table) $tbl = $name; else { $alias = key($name); $tbl = current($name); if (is_string($tbl)) $tbl = new Table($tbl); } $this->joins[] = array( 'name' => $tbl, 'on' => $on, 'type' => $type, 'alias' => $alias ); $this->setup[self::JOINS] = $this->joins; return $this; } public function group($group) { if(is_array($group)) { foreach($group as $o) $this->group[] = $o; } else $this->group[] = $group; $this->setup[self::GROUP] = $this->group; return $this; } /** * Create where clause * * @param Where|\Closure|string|array $predicate * @param string $combination * One of the OP_* constants from Predicate\PredicateSet * @return $this */ public function having($predicate, $combination = iExprBool::OP_AND) { if($predicate instanceof Having) $this->having = $predicate; else $this->having->addPredicates($predicate, $combination); $this->setup[self::HAVING] = $this->having; return $this; } /** * * @param int $offset * @return $this */ public function offset($offset) { if(!is_numeric($offset)) throw new \InvalidArgumentException(sprintf('%s expects parameter to be numeric, "%s" given', __METHOD__, (is_object($offset) ? get_class($offset) : gettype($offset)))); $this->setup[self::OFFSET] = $offset; return $this; } /** * * @param Select $select * @return $this * @throws \InvalidArgumentException */ public function combine(Select $select, $type = self::COMBINE_UNION) { $this->setup[self::COMBINE][] = [ $select, $type ]; return $this; } /** * * @param string $part * @return Select * @throws \BadMethodCallException */ public function reset($part) { switch($part) { case self::QUANTIFIER: $this->quantifier = null; break; case self::COLUMNS: $this->columns = array(); break; case self::JOINS: $this->joins = array(); break; case self::WHERE: $this->where = new Where(); break; case self::GROUP: $this->group = null; break; case self::HAVING: $this->having = new Having(); break; case self::LIMIT: $this->limit = null; break; case self::OFFSET: $this->offset = null; break; case self::ORDER: $this->order = array(); break; case self::COMBINE: $this->combine = array(); break; } return $this; } /** * Get SQL string for statement * * @param null|iDialect $dialect * If null, defaults to Sql92 * @return string */ public function getSql(iDialect $dialect = null) { $dialect = $dialect ? $dialect : new \Mammut\DB\Sql\Dialect\Sql92(); $sql = $dialect->getSelectSQL($this->setup); return $sql; } }