'array', 'limit' => array('integer', 'NULL'), 'offset' => array('integer', 'NULL'), 'group_by' => array('string', 'NULL'), 'type' => 'string');
/**
* UNION queries
* @var array
*/
protected $_union = array();
/**
* Generates a query in format that can be executed on current database implementation
*
*/
public abstract function query();
/**
* Creates a new query
*
* @param DB $db Database connection
* @param string $type Query type. Available types: select, update, insert, delete, count
* @return void
*/
public function __construct($db, $type)
{
$this->_db = $db;
$this->_type = $type;
}
/**
* Sets fields to be queried from the database. You can add aliases to the fields
* by passing them as:
*
* array('field_name','alias')
*
* Example: $query->fields('id', array('name', 'fairy_name'))
*
* @param mixed $field,... Fields to be selected from the table
* @return mixed If no parameters are passed returns current array of fields,
* otherwise returns self.
*/
public function fields()
{
$p = func_get_args();
if (empty($p))
{
return $this->_fields;
}
else
{
$this->_fields = $p;
}
return $this;
}
/**
* Sets the table to perform operations on, also supports subqueries
*
* @param string|Query_database|Expression_database $table table to select from
* @param string $alias Alias for this table
* @return mixed Returns self if a table is passed, otherwise returns the table
*/
public function table($table = null, $alias = null)
{
if ($table == null)
{
return is_array($this->_table) ? $this->_table[1] : $this->_table;
}
if (!is_string($table) && $alias == null)
{
$alias = $this->add_alias();
}
$this->_table = $alias == null ? $table : array($table, $alias);
return $this;
}
/**
* Magic methods to create methods for all generic query parts
*
* @param string $method Name of the method to call
* @param array $args Array of parameters
* @return mixed If no arguments are passed returns the current value of the property,
* otherwise returns self.
* @throws \Exception If method doesn't exist
* @throws \Exception If value is of incorrect type
* @see $methods
*/
public function __call($method, $args)
{
if (isset($this->methods[$method]))
{
$property = '_'.$method;
if (empty($args))
{
return $this->$property;
}
$val = $args[0];
if (is_numeric($val))
{
$val = (int) $val;
}
$allowed_types = $this->methods[$method];
if (!is_array($allowed_types))
{
$allowed_types = array($allowed_types);
}
if (!in_array(gettype($val), $allowed_types))
{
throw new \Exception("Method '{$method}' only accepts values of type: ".implode(' or ', $allowed_types).", '{$val}' was passed");
}
$this->$property = $val;
return $this;
}
throw new \Exception("Method '{$method}' doesn't exist.");
}
/**
* Executes the query
*
* @return object Executes current query on its database connection
* @see DB
*/
public function execute()
{
$query = $this->query();
$result = $this->_db->execute($query[0], $query[1]);
if ($this->_type == 'count')
{
return $result->get('count');
}
return $result;
}
/**
* Adds a joined table to the query.
*
* @param string $table Table to join
* @param array $conds Conditions to join tables on, same behavior as with where() method
* @param string $type Type of join. Defaults to 'left'
* @return Query_Database Returns self
* @see where()
*/
public function join($table, $conds, $type = 'left')
{
$this->_joins[] = array($table, $type, $this->get_condition_part($conds));
return $this;
}
/**
* Sets conditions for aggregate functions, same behavior as with where() method
*
* @return Query_Database Returns self
* @see where()
*/
public function having()
{
$p = func_get_args();
$cond = $this->get_condition_part($p);
$this->_having = array_merge($this->_having, array($cond));
return $this;
}
/**
* Adds a column to ordering parameters.
*
* @param string $column Column to order by
* @param string $dir Ordering direction.
* @return Query_Database Returns self
* @throws \Exception If ordering direction isn't DESC or ASC
*/
public function order_by($column, $dir = 'ASC')
{
$dir = strtoupper($dir);
if ($dir != 'DESC' && $dir != 'ASC')
{
throw new \Exception("Invalid sorting direction {$dir} specified");
}
$this->_order_by[] = array($column, $dir);
return $this;
}
/**
* Sets conditions for the query.
* Can be called in many ways, examples:
* Shorthand equals condition:
*
* $q->where('name', 'Tinkerbell')
*
* Conditions with operator:
*
* $q->where('id', '>', 3)
*
* OR logic:
*
* $q->where('or', array('name', 'Tinkerbell'))
*
* OR logic with operator
*
* ->where('or', array('id', '>', 3))
*
* Arrays represent brackets. e.g
*
* $q->where('name', 'Tinkerbell')
* ->where('or', array(
* array('id', '>', 7),
* array('id', '<', 15)
* );
* //Will produce "WHERE `name`='Tinkerbell' OR (`id` > 7 AND `id` < 15)"
*
* Multiple calls to where() append new conditions to previous ones
*
* @param mixed $column Column name, logic parameter 'OR' or 'AND' or an array of conditions
* @param mixed $operator Condition value, operator or an array of parameters
* @param mixed $val Condition value
*
* @return Query_Database Returns self
*/
public function where()
{
$p = func_get_args();
$cond = $this->get_condition_part($p);
$this->_conditions = array_merge($this->_conditions, array($cond));
return $this;
}
/**
* Recursively builds condition arrays for methods like where(), having()
*
* @param array $p Parameters passed to the method
* @return array Array in condition format
* @throws \Exception If condition format is incorrect
*/
private function get_condition_part($p)
{
if (is_string($p[0]) && (strtolower($p[0]) == 'or' || strtolower($p[0]) == 'and') && isset($p[1]) && is_array($p[1]))
{
$cond = $this->get_condition_part($p[1]);
$cond['logic'] = strtolower($p[0]);
return $cond;
}
if (is_array($p[0]))
{
if (count($p) == 1)
{
return $this->get_condition_part($p[0]);
}
$conds = array();
foreach ($p as $q)
{
$conds[] = $this->get_condition_part($q);
}
if (count($conds) == 1)
{
return $conds;
}
return array('logic' => 'and', 'conditions' => $conds);
}
if ((is_string($p[0]) || $p[0] instanceof \PHPixie\DB\Expression) && isset($p[1]))
{
if (is_string($p[0]) && strpos($p[0], '.') === false)
{
$p[0] = $this->last_alias().'.'.$p[0];
}
return array(
'logic' => 'and',
'conditions' => array(
'field' => $p[0],
'operator' => isset($p[2]) ? $p[1] : '=',
'value' => isset($p[2]) ? $p[2] : $p[1]
)
);
}
throw new \Exception('Incorrect conditional statement passed');
}
/**
* Adds a UNION to the query
*
* @param Query_Database|Expression_Database $query Query for the UNION
* @param string $all whether to do a UNION ALL, e.g. keep duplicate rows
* @return Query_Database Returns self
*/
public function union($query,$all=true) {
$this->_union[] = array($query,$all);
return $this;
}
/**
* Gets last generated alias
*
* @return string Last generated alias. If no alias were created returns table name.
*/
public function last_alias()
{
if ($this->_alias === null)
{
return $this->_table;
}
return 'a'.$this->_alias;
}
/**
* Generates new alias. Useful for dynamically adding aliases to joins.
* Alias is just a letter 'a' with an incremented number.
*
* @return string New alias
*/
public function add_alias()
{
if ($this->_alias === null)
{
$this->_alias = 0;
}
else
{
$this->_alias++;
}
return $this->last_alias();
}
}