diff --git a/Doctrine/Hydrate.php b/Doctrine/Hydrate.php index 9ec2f2e47..9e023da94 100644 --- a/Doctrine/Hydrate.php +++ b/Doctrine/Hydrate.php @@ -30,37 +30,39 @@ Doctrine::autoload('Doctrine_Access'); */ abstract class Doctrine_Hydrate extends Doctrine_Access { /** - * @var array $fetchmodes an array containing all fetchmodes + * @var array $fetchmodes an array containing all fetchmodes */ protected $fetchModes = array(); /** - * @var array $tables an array containing all the tables used in the query + * @var array $tables an array containing all the tables used in the query */ protected $tables = array(); /** - * @var array $collections an array containing all collections this parser has created/will create + * @var array $collections an array containing all collections this parser has created/will create */ protected $collections = array(); /** - * @var array $joins an array containing all table joins + * @var array $joins an array containing all table joins */ protected $joins = array(); /** - * @var array $data fetched data + * @var array $data fetched data */ protected $data = array(); /** - * @var Doctrine_Connection $connection Doctrine_Connection object + * @var Doctrine_Connection $connection Doctrine_Connection object */ protected $connection; /** - * @var Doctrine_View $view Doctrine_View object + * @var Doctrine_View $view Doctrine_View object */ protected $view; protected $inheritanceApplied = false; - + /** + * @var boolean $aggregate + */ protected $aggregate = false; /** * @var array $tableAliases @@ -245,7 +247,13 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { else $query = $this->view->getSelectSql(); + if($this->isLimitSubqueryUsed()) + $params = array_merge($params, $params); + $stmt = $this->connection->execute($query,$params); + + if($this->aggregate) + return $stmt->fetchAll(PDO::FETCH_ASSOC); switch(count($this->tables)): case 0: @@ -257,8 +265,6 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { $name = $this->tables[$keys[0]]->getComponentName(); - $stmt = $this->connection->execute($query,$params); - while($data = $stmt->fetch(PDO::FETCH_ASSOC)): foreach($data as $key => $value): @@ -280,21 +286,19 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { default: $keys = array_keys($this->tables); $root = $keys[0]; - - if($this->isLimitSubqueryUsed()) - $params = array_merge($params, $params); - - - - $stmt = $this->connection->execute($query,$params); $previd = array(); $coll = $this->getCollection($root); $prev[$root] = $coll; + + if($this->aggregate) + $return = Doctrine::FETCH_ARRAY; + $array = $this->parseData($stmt); + if($return == Doctrine::FETCH_VHOLDER) { return $this->hydrateHolders($array); } elseif($return == Doctrine::FETCH_ARRAY) diff --git a/Doctrine/Query.php b/Doctrine/Query.php index 49cd5cdf7..d1cf99cc7 100644 --- a/Doctrine/Query.php +++ b/Doctrine/Query.php @@ -532,7 +532,19 @@ class Doctrine_Query extends Doctrine_Hydrate { } return $term; } - + /** + * sqlExplode + * + * explodes a string into array using custom brackets and + * quote delimeters + * + * @param string $str + * @param string $d the delimeter which explodes the string + * @param string $e1 the first bracket, usually '(' + * @param string $e2 the second bracket, usually ')' + * + * @return array + */ public static function sqlExplode($str,$d = " ",$e1 = '(',$e2 = ')') { $str = explode("$d",$str); $i = 0; @@ -724,7 +736,7 @@ class Doctrine_Query extends Doctrine_Hydrate { * @param string $currPath * @return void */ - final public function parseFields($fullName, $tableName, $exploded, $currPath) { + final public function parseFields($fullName, $tableName, array $exploded, $currPath) { $table = $this->tables[$tableName]; $fields = array(); @@ -732,20 +744,71 @@ class Doctrine_Query extends Doctrine_Hydrate { if(strpos($fullName, "-") === false) { $fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE); - if(isset($exploded[1])) - $fields = explode(",",substr($exploded[1],0,-1)); + if(isset($exploded[1])) { + if(count($exploded) > 2) { + $fields = $this->parseAggregateValues($fullName, $tableName, $exploded, $currPath); + } elseif(count($exploded) == 2) { + $fields = explode(",",substr($exploded[1],0,-1)); + } + } + } else { + if(isset($exploded[1])) { + $fetchmode = $this->parseFetchMode($exploded[1]); + } else + $fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE); - } else { - if(isset($exploded[1])) { - $fetchmode = $this->parseFetchMode($exploded[1]); - } else - $fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE); + if(isset($exploded[2])) { + if(substr_count($exploded[2], ")") > 1) { - if(isset($exploded[2])) + } else { $fields = explode(",",substr($exploded[2],0,-1)); + } } + } + if( ! $this->aggregate) $this->loadFields($table, $fetchmode, $fields, $currPath); } + public function parseAggregateFunction($func,$reference) { + $pos = strpos($func,"("); + + if($pos !== false) { + $funcs = array(); + + $name = substr($func, 0, $pos); + $func = substr($func, ($pos + 1), -1); + $params = Doctrine_Query::bracketExplode($func, ",", "(", ")"); + + foreach($params as $k => $param) { + $params[$k] = $this->parseAggregateFunction($param,$reference); + } + + $funcs = $name."(".implode(", ", $params).")"; + + return $funcs; + + } else { + if( ! is_numeric($func)) { + + $func = $this->getTableAlias($reference).".".$func; + + return $func; + } else { + return $func; + } + } + } + final public function parseAggregateValues($fullName, $tableName, array $exploded, $currPath) { + $this->aggregate = true; + $pos = strpos($fullName,"("); + $name = substr($fullName, 0, $pos); + $string = substr($fullName, ($pos + 1), -1); + + $exploded = Doctrine_Query::bracketExplode($string, ','); + foreach($exploded as $k => $value) { + $exploded[$k] = $this->parseAggregateFunction($value, $currPath); + $this->parts["select"][] = $exploded[$k]; + } + } } ?> diff --git a/tests/QueryTestCase.php b/tests/QueryTestCase.php index bf2b44e5b..7420cd588 100644 --- a/tests/QueryTestCase.php +++ b/tests/QueryTestCase.php @@ -24,16 +24,37 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { parent::prepareTables(); } - /** - public function testQueryPart() { - $this->query->from[] = "User.Phonenumber"; - $this->query->from[] = "User.Email"; + public function testSelectingAggregateValues() { + $q = new Doctrine_Query(); + $q->from("User(COUNT(1), MAX(name))"); + $array = $q->execute(); + $this->assertTrue(is_array($array)); + $this->assertEqual($array, array(array('COUNT(1)' => '8', 'MAX(entity.name)' => 'zYne'))); + $this->assertEqual($q->getQuery(), "SELECT COUNT(1), MAX(entity.name) FROM entity WHERE (entity.type = 0)"); + + $q = new Doctrine_Query(); + $q->from("Phonenumber(COUNT(1))"); + + $array = $q->execute(); + $this->assertTrue(is_array($array)); + $this->assertEqual($array, array(array('COUNT(1)' => '15'))); + $this->assertEqual($q->getQuery(), "SELECT COUNT(1) FROM phonenumber"); + + $q = new Doctrine_Query(); + $q->from("User.Phonenumber(COUNT(id))"); + $array = $q->execute(); + $this->assertTrue(is_array($array)); + + $this->assertEqual($array[0]['COUNT(phonenumber.id)'], 14); + $this->assertEqual($q->getQuery(), "SELECT entity.id AS entity__id, entity.name AS entity__name, entity.loginname AS entity__loginname, entity.password AS entity__password, entity.type AS entity__type, entity.created AS entity__created, entity.updated AS entity__updated, entity.email_id AS entity__email_id, COUNT(phonenumber.id) FROM entity LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id WHERE (entity.type = 0)"); + + $q = new Doctrine_Query(); + $q->from("User(MAX(id)).Email(MIN(address))"); + $array = $q->execute(); + $this->assertTrue(is_array($array)); - $users = $this->query->execute(); - $this->assertEqual($users->count(), 8); } - */ public function testMultipleFetching() { $count = $this->dbh->count(); diff --git a/tests/RecordTestCase.php b/tests/RecordTestCase.php index 11fdc2705..2ed207cc8 100644 --- a/tests/RecordTestCase.php +++ b/tests/RecordTestCase.php @@ -93,7 +93,13 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $this->assertEqual($coll->count(), 1); } - + + + public function testDateTimeType() { + $date = new DateTest(); + + + } public function testEnumType() { $enum = new EnumTest(); $enum->status = "open"; diff --git a/tests/classes.php b/tests/classes.php index fa625d924..d067af5ff 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -386,7 +386,11 @@ class Validator_Test extends Doctrine_Record { $this->hasColumn("myemail2", "string", 100, "email|notblank"); } } - +class DateTest extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("date", "date", 20); + } +} class Tag extends Doctrine_Record {