<?php
/**
* @version 1.0.0
* @category Anahita Social Engineâ¢
* @copyright Copyright (C) 2008 - 2010 rmdStudio Inc. and Peerglobe Technology Inc. All rights reserved.
* @license GNU GPLv2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
* @link http://www.anahitapolis.com
*/
class AnDomainQuery extends KDatabaseQuery implements KMixinInterface
{
protected $_mapper;
protected $_unique_conditions = array();
protected $_fields_map;
protected $_raw_query;
public function __construct($options = array())
{
$this->_mapper = $options['mapper'];
parent::__construct(array('adapter'=>$this->getMapper()->getAdapter()));
$this->_raw_query = $this->getMapper()->rawQuery();
$this->from = $this->_raw_query->from;
$this->update($this->_raw_query, array('join','where','group','order'));
$this->_fields_map = $this->_mapper->attrKeyPathsToField();
}
public function getMapper()
{
return $this->_mapper;
}
public function getModel()
{
return $this->getMapper()->getModel();
}
public function join($type, $table, $condition)
{
$conditions = array();
if ( is_array($condition) ) {
foreach($condition as $key => $value) {
if ( is_numeric($key) ) {
$conditions[] = $value;
continue;
} else if ( isset($this->_fields_map[$key]) ) {
$key = $this->_fields_map[$key];
}
$conditions[] = $key.' = '.$value;
}
} else {
$conditions = $condition;
}
parent::join($type, $table, $conditions);
return $this;
}
public function uniqueConditions()
{
return $this->_unique_conditions;
}
/**
*
* @return
* @param $property Object
* @param $constraint Object
* @param $value Object[optional]
* @param $condition Object[optional]
*/
protected $_where_statements = array();
public function where( $key, $constraint, $value = null, $condition = 'AND' )
{
//is query being used to find a unique entity
$unique_keys = $this->getMapper()->getUniqueKeys();
if ( isset($unique_keys[$key]) && $constraint != 'IN' ) {
$this->_unique_conditions[$key] = $value;
}
$property = $this->getMapper()->getProperty($key);
if ( isset($this->_fields_map[$key]) || !$property ) {
$key = isset($this->_fields_map[$key]) ? $this->_fields_map[$key] : $key;
if ( $value === false ) {
$value = 0;
} else if ( is_null($value) ) {
$value = '';
}
return parent::where($key, $constraint, $value, $condition);
}
if ( $property->getIdentifier()->name == 'manytomany' ) {
$property->mergeQueryWithTargetQuery($this, $key, array(
'where'=> array(
'constraint' => $constraint,
'value' => $value,
'condition' => $condition
)
) );
return $this;
}
$table_fields = $property->getTableFields();
if ( (is_array($value) || $value instanceof KObjectArray)) {
$values = $value;
$constraint = 'IN';
$field_array = array();
foreach($table_fields as $table_field)
$field_array[$table_field] = array();
foreach($values as $value) {
$table_values = $property->getTableValues( $value );
foreach($table_values as $index => $table_value) {
$table_field = $table_fields[$index];
$field_array[ $table_field ][] = $table_value;
}
}
foreach($field_array as $field => $values) {
$this->where($field,'IN', array_unique($values), $condition);
}
} else {
$table_fields = $property->getTableFields();
$table_values = $property->getTableValues( $value );
foreach($table_fields as $index => $field) {
$value = $table_values[$index];
$this->where($field, $constraint, $value, $condition);
}
}
return $this;
}
public function group($keys)
{
settype($keys, 'array');
foreach($keys as $key)
{
$property = $this->getMapper()->getProperty($key);
if ( !$property ) {
$key = isset($this->_fields_map[$key]) ? $this->_fields_map[$key] : $key;
parent::group($key);
continue;
}
$fields = $property->getTableFields();
foreach($fields as $field) {
parent::group($field);
}
}
return $this;
}
public function order( $keys, $direction = 'ASC' )
{
settype($keys, 'array');
foreach($keys as $key)
{
$property = $this->getMapper()->getProperty($key);
if ( !$property ) {
$key = isset($this->_fields_map[$key]) ? $this->_fields_map[$key] : $key;
parent::where($key, $direction);
continue;
}
$fields = $property->getTableFields();
foreach($fields as $field) {
parent::order($field, $direction);
}
}
return $this;
}
/**
*
* @return
* @param $query Object
*/
public function update($query, array $keys = array('join','where'))
{
foreach($keys as $key) {
if ( $key == 'where' && count($query->where) && count($this->where) ) {
$this->where[] = 'AND';
}
$this->$key = is_array($this->$key) ?
array_merge($this->$key, $query->$key) :
$query->$key;
}
return $this;
}
public function merge($query)
{
if ( count($query->where) && count($this->where) ) {
$this->where[] = 'AND';
}
$this->operation = $query->operation;
$this->order = array_merge($this->order, $query->order);
$this->where = array_merge($this->where, $query->where);
$this->limit = $query->limit;
return $this;
}
public function getOffset()
{
return $this->offset;
}
public function getLimit()
{
return $this->limit;
}
/**
* Return min of the property
* @return Integer
* @param $name String
*/
public function min($property)
{
$query = clone $this;
$query->columns = array();
$attribute = $this->getMapper()->getAttribute($property);
$query->limit(null);
$query->operation = 'SELECT min('.$attribute.')';
$min = $this->getAdapter()->fetchResult($query);
return $min;
}
/**
* Return max of the property
* @return Integer
* @param $property String
*/
public function max($property)
{
$query = clone $this;
$query->columns = array();
$attribute = $this->getMapper()->getAttribute($property);
$query->limit(null);
$query->operation = 'SELECT max('.$attribute.')';
$max = $this->getAdapter()->fetchResult($query);
return $max;
}
/**
* Count total number of entities
* @return Integer
*/
public function count()
{
$query = clone $this;
$query->operation = 'SELECT count(*)';
$query->columns = array();
$query->limit(null);
$count = $this->getAdapter()->fetchResult($query);
return $count;
}
/**
* Fetch an entity
* @return Entity
*/
public function fetch()
{
return $this->getMapper()->getRepository()->fetch($this);
}
/**
* Fetch a collection of entities
* @return Collection
*/
public function fetchAll()
{
return $this->getMapper()->getRepository()->fetchAll($this);
}
/**
* Get the methods that are available for mixin.
*
* @return array An array of methods
*/
public function getMixableMethods()
{
$remove = array('__construct', '__destruct');
$methods = array_diff(get_class_methods($this), $remove);
return $methods;
}
protected $_selected_properties = array();
public function getSelectedProperties()
{
return array_unique($this->_selected_properties);
}
public function select($name)
{
if ( is_array($name) )
foreach($name as $onename)
$this->select($onename);
else if ( $property = $this->_mapper->getProperty($name) ) {
if ( !$property->isSelectable() ) return;
$this->_selected_properties[] = $property->getName();
$fields = $property->getTableFields();
foreach($fields as $field)
{
if ( strpos($field, '(') ) // a mysql function
{
$this->columns[] = $field;
} else parent::select( $field.' AS '.str_replace('.','_',$field) );
}
} else {
parent::select($name);
}
return $this;
}
/**
*
*/
static $_default_columns = array();
/**
* what is that ???
* @return
*/
public function __toString()
{
if ( !$this->operation )
$this->operation = 'SELECT';
$operation = $this->operation;
if ( $this->operation == 'SELECT' || $this->operation == 'SELECT DISTINCT ') {
if ( !count($this->_selected_properties) ) {
//cache the default columns for future queries
$model = $this->getMapper()->getModel();
if ( !isset(self::$_default_columns[ $model ]) ) {
$properies = $this->getMapper()->getProperties();
foreach($properies as $property) {
$this->select($property->getName());
}
self::$_default_columns[$model] = $this->columns;
}
$this->columns = self::$_default_columns[$model];
} else {
$keys = array_keys($this->getMapper()->getUniqueKeys());
$this->select( $keys );
}
}
$query = '';
$query .= $operation.PHP_EOL;
if (!empty($this->columns)) {
$query .= implode(' , ', $this->columns).PHP_EOL;
}
if (!empty($this->from)) {
$query .= ' FROM '.implode(' , ', $this->from).PHP_EOL;
}
if (!empty($this->join))
{
$joins = array();
foreach ($this->join as $join)
{
$tmp = '';
if (! empty($join['type'])) {
$tmp .= $join['type'] . ' ';
}
$tmp .= 'JOIN ' . $join['table'];
$tmp .= ' ON ' . implode(' AND ', $join['condition']);
$joins[] = $tmp;
}
$query .= implode(PHP_EOL, $joins) .PHP_EOL;
}
if (!empty($this->where)) {
//print implode(' ', $this->_where_statements);
$where = implode(' ', $this->where);
$query .= ' WHERE '.$where.PHP_EOL;
}
if (!empty($this->group)) {
$query .= ' GROUP BY '.implode(' , ', $this->group).PHP_EOL;
}
if (!empty($this->having)) {
$query .= ' HAVING '.implode(' , ', $this->having).PHP_EOL;
}
if (!empty($this->order) )
{
$query .= 'ORDER BY ';
$list = array();
foreach ($this->order as $order) {
$list[] = $order['column'].' '.$order['direction'];
}
$query .= implode(' , ', $list) . PHP_EOL;
}
if (!empty($this->limit)) {
$query .= ' LIMIT '.$this->offset.' , '.$this->limit.PHP_EOL;
}
$query = $this->getAdapter()->replaceTablePrefix( $query );
return $query;
}
}