From cf939c6d3a01ccc82ceca9447cb78aeb6e688c1b Mon Sep 17 00:00:00 2001 From: zYne Date: Sat, 23 Dec 2006 22:45:36 +0000 Subject: [PATCH] Doctrine_Hook first draft + test cases --- lib/Doctrine/Hook.php | 100 ++++++++++++++++++++++++-- lib/Doctrine/Hook/Equal.php | 50 +++++++++++++ lib/Doctrine/Hook/Integer.php | 73 +++++++++++++++++++ lib/Doctrine/Hook/Parser.php | 57 +++++++++++++++ lib/Doctrine/Hook/Parser/Complex.php | 98 +++++++++++++++++++++++++ lib/Doctrine/Hook/WordLike.php | 56 +++++++++++++++ lib/Doctrine/Hydrate.php | 30 +++++--- lib/Doctrine/Query.php | 41 +++++------ lib/Doctrine/Query/Condition.php | 17 ++--- manual/documentation.php | 6 ++ tests/ExportReporterTestCase.php | 19 +++++ tests/HookTestCase.php | 57 +++++++++++++++ tests/QueryAggregateValueTestCase.php | 95 ++++++++++++++++++++++++ tests/run.php | 27 +++---- 14 files changed, 664 insertions(+), 62 deletions(-) create mode 100644 lib/Doctrine/Hook/Equal.php create mode 100644 lib/Doctrine/Hook/Integer.php create mode 100644 lib/Doctrine/Hook/Parser.php create mode 100644 lib/Doctrine/Hook/Parser/Complex.php create mode 100644 lib/Doctrine/Hook/WordLike.php create mode 100644 tests/ExportReporterTestCase.php create mode 100644 tests/HookTestCase.php create mode 100644 tests/QueryAggregateValueTestCase.php diff --git a/lib/Doctrine/Hook.php b/lib/Doctrine/Hook.php index 2ba295f13..7ed9e72dc 100644 --- a/lib/Doctrine/Hook.php +++ b/lib/Doctrine/Hook.php @@ -34,11 +34,37 @@ class Doctrine_Hook { /** * @var Doctrine_Query $query the base query */ - private $query; + protected $query; /** * @var array $joins the optional joins of the base query */ - private $joins; + protected $joins; + /** + * @var array $hooks hooks array + */ + protected $hooks = array( + 'where', + 'orderby', + 'limit', + 'offset' + ); + /** + * @var array $params query parameters + */ + protected $params = array(); + /** + * @var array $fieldParsers + */ + protected $fieldParsers = array(); + + /** + * @var array $typeParsers + */ + protected $typeParsers = array( + 'char' => 'Doctrine_Hook_WordLike', + 'string' => 'Doctrine_Hook_WordLike', + 'integer' => 'Doctrine_Hook_Integer', + ); /** * @param Doctrine_Query $query the base query @@ -51,16 +77,82 @@ class Doctrine_Hook { $this->query = $query; } } + public function buildQuery() { + $where = array(); + $from = array(); + $params = array(); + + + $component = $this->table->getComponentName(); + + $data = self::makeFlat($this->where); + + foreach($data as $k => $v) { + if(trim($v) == '') { + unset($data[$k]); + } + } + + $orderby = array(); + + if(isset($this->hooks['orderby'])) { + $e = explode(" ",$this->hooks['orderby']); + + $orderComponent = $e[0]; + + if(in_array($orderComponent, $this->fields)) { + if(isset($e[1]) && ($e[1] == "ASC" || $e[1] == "DESC")) { + $orderby[] = $component.".".$e[0]." ".$e[1]; + } + } + + } + + } + public function getQuery() { + return $this->query; + } public function leftJoin($dql) { } public function innerJoin($dql) { } + /** + * hookWhere + * + * @param array $params an array of query where parameters + */ public function hookWhere(array $params) { + foreach($params as $name => $value) { + $e = explode('.', $name); + + if(count($e) == 2) { + list($alias, $column) = $e; + $tableAlias = $this->query->getTableAlias($alias); + $table = $this->query->getTable($tableAlias); + + if($def = $table->getDefinitionOf($column)) { + + if(isset($this->typeParsers[$def[0]])) { + $name = $this->typeParsers[$def[0]]; + $parser = new $name; + } + + $parser->parse($alias, $column, $value); + + $this->query->addWhere($parser->getCondition()); + $this->params += $parser->getParams(); + } + } + } + $this->params += $params; } - public function hookOrderby(array $params) { + /** + * @param integer $limit + */ + public function hookOrderby($params) { } /** @@ -73,7 +165,7 @@ class Doctrine_Hook { * @param integer $offset */ public function hookOffset($offset) { - + } public function setWhereHooks() { diff --git a/lib/Doctrine/Hook/Equal.php b/lib/Doctrine/Hook/Equal.php new file mode 100644 index 000000000..9bd263120 --- /dev/null +++ b/lib/Doctrine/Hook/Equal.php @@ -0,0 +1,50 @@ +. + */ +Doctrine::autoload('Doctrine_Hook_Parser'); +/** + * Doctrine_Hook_Equal + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +class Doctrine_Hook_Equal extends Doctrine_Hook_Parser { + /** + * parse + * Parses given field and field value to DQL condition + * and parameters. This method should always return + * prepared statement conditions (conditions that use + * placeholders instead of literal values). + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + public function parse($alias, $field, $value) { + $this->params = (array) $value; + $this->condition = $alias . '.' . $field . ' = ?'; + } +} diff --git a/lib/Doctrine/Hook/Integer.php b/lib/Doctrine/Hook/Integer.php new file mode 100644 index 000000000..b36a6fbd0 --- /dev/null +++ b/lib/Doctrine/Hook/Integer.php @@ -0,0 +1,73 @@ +. + */ +Doctrine::autoload('Doctrine_Hook_Parser_Complex'); +/** + * Doctrine_Hook_Integer + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +class Doctrine_Hook_Integer extends Doctrine_Hook_Parser_Complex { + /** + * parse + * Parses given field and field value to DQL condition + * and parameters. This method should always return + * prepared statement conditions (conditions that use + * placeholders instead of literal values). + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + public function parseSingle($alias, $field, $value) { + $e = explode(' ', $value); + + foreach($e as $v) { + $v = trim($v); + + $e2 = explode('-', $v); + + $name = $alias. '.' . $field; + + if(count($e2) == 1) { + // one '-' found + + $a[] = $name . ' = ?'; + + $this->params[] = $v; + } else { + // more than one '-' found + + $a[] = '(' . $name . ' > ? AND ' . $name . ' < ?)'; + + $this->params += array($e2[0], $e2[1]); + } + + } + return implode(' OR ', $a); + } +} diff --git a/lib/Doctrine/Hook/Parser.php b/lib/Doctrine/Hook/Parser.php new file mode 100644 index 000000000..cdba2ca88 --- /dev/null +++ b/lib/Doctrine/Hook/Parser.php @@ -0,0 +1,57 @@ +. + */ + +/** + * Doctrine_Hook_Parser + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +abstract class Doctrine_Hook_Parser { + protected $condition; + protected $params = array(); + + public function getCondition() { + return $this->condition; + } + + public function getParams() { + return $this->params; + } + /** + * parse + * Parses given field and field value to DQL condition + * and parameters. This method should always return + * prepared statement conditions (conditions that use + * placeholders instead of literal values). + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + abstract public function parse($alias, $field, $value); +} diff --git a/lib/Doctrine/Hook/Parser/Complex.php b/lib/Doctrine/Hook/Parser/Complex.php new file mode 100644 index 000000000..3a2d88df2 --- /dev/null +++ b/lib/Doctrine/Hook/Parser/Complex.php @@ -0,0 +1,98 @@ +. + */ +Doctrine::autoload('Doctrine_Hook_Parser'); +/** + * Doctrine_Hook_Parser_Complex + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +abstract class Doctrine_Hook_Parser_Complex extends Doctrine_Hook_Parser { + /** + * parse + * Parses given field and field value to DQL condition + * and parameters. This method should always return + * prepared statement conditions (conditions that use + * placeholders instead of literal values). + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + public function parse($alias, $field, $value) { + $this->condition = $this->parseClause($alias, $field, $value); + } + /** + * parseClause + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + public function parseClause($alias, $field, $value) { + $parts = Doctrine_Query::bracketExplode($value, ' AND ', '(', ')'); + + if(count($parts) > 1) { + $ret = array(); + foreach($parts as $part) { + $part = Doctrine_Query::bracketTrim($part, '(', ')'); + $ret[] = $this->parseSingle($alias, $field, $part); + } + + $r = implode(' AND ', $ret); + } else { + $parts = Doctrine_Query::bracketExplode($value, ' OR ', '(', ')'); + if(count($parts) > 1) { + $ret = array(); + foreach($parts as $part) { + $part = Doctrine_Query::bracketTrim($part, '(', ')'); + $ret[] = $this->parseClause($alias, $field, $part); + } + + $r = implode(' OR ', $ret); + } else { + if(substr($parts[0],0,1) == '(' && substr($parts[0],-1) == ')') { + return $this->parseClause(substr($parts[0],1,-1)); + } else { + $ret = $this->parseSingle($alias, $field, $parts[0]); + return $ret; + } + } + } + return '(' . $r . ')'; + } + /** + * parseSingle + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + abstract public function parseSingle($alias, $field, $value); +} diff --git a/lib/Doctrine/Hook/WordLike.php b/lib/Doctrine/Hook/WordLike.php new file mode 100644 index 000000000..b3ddc5713 --- /dev/null +++ b/lib/Doctrine/Hook/WordLike.php @@ -0,0 +1,56 @@ +. + */ +Doctrine::autoload('Doctrine_Hook_Parser'); +/** + * Doctrine_Hook_WordLike + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +class Doctrine_Hook_WordLike extends Doctrine_Hook_Parser_Complex { + /** + * parse + * Parses given field and field value to DQL condition + * and parameters. This method should always return + * prepared statement conditions (conditions that use + * placeholders instead of literal values). + * + * @param string $alias component alias + * @param string $field the field name + * @param mixed $value the value of the field + * @return void + */ + public function parseSingle($alias, $field, $value) { + $e2 = explode(' ',$value); + + foreach($e2 as $v) { + $v = trim($v); + $a[] = $alias. '.' . $field . ' LIKE ?'; + $this->params[] = $v . '%'; + } + return implode(' OR ', $a); + } +} diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index 8eb22ee22..e1e82bd3a 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -82,9 +82,7 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { * @var array $tableIndexes */ protected $tableIndexes = array(); - - protected $components = array(); - + protected $pendingAggregates = array(); protected $aggregateMap = array(); @@ -143,6 +141,14 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { public function getTableIndexes() { return $this->tableIndexes; } + /** + * getTables + * + * @return array + */ + public function getTables() { + return $this->tables; + } /** * copyAliases * @@ -160,7 +166,7 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { $s = array_search($path, $this->compAliases); if($s === false) return $path; - + return $s; } /** @@ -256,8 +262,9 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { } /** * getView + * returns the view associated with this query object (if any) * - * @return Doctrine_View + * @return Doctrine_View the view associated with this query object */ public function getView() { return $this->view; @@ -637,10 +644,10 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { * parse the data into two-dimensional array */ foreach($data as $key => $value): - $e = explode("__",$key); + $e = explode('__', $key); - $field = strtolower( array_pop($e) ); - $component = strtolower( implode("__",$e) ); + $field = strtolower(array_pop($e)); + $component = strtolower(implode('__', $e)); $data[$component][$field] = $value; @@ -656,10 +663,13 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { * returns a Doctrine_Table for given name * * @param string $name component name - * @return Doctrine_Table + * @return Doctrine_Table|boolean */ public function getTable($name) { - return $this->tables[$name]; + if(isset($this->tables[$name])) + return $this->tables[$name]; + + return false; } /** * @return string returns a string representation of this object diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 0ab37b50c..11aa35826 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -65,7 +65,9 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { private $relationStack = array(); private $isDistinct = false; - + /** + * @var array $pendingFields + */ private $pendingFields = array(); /** * @var integer $type the query type @@ -102,13 +104,10 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { public function processPendingFields($componentAlias) { $tableAlias = $this->getTableAlias($componentAlias); - - $componentPath = $this->compAliases[$componentAlias]; - - if( ! isset($this->components[$componentPath])) + if( ! isset($this->tables[$tableAlias])) throw new Doctrine_Query_Exception('Unknown component path '.$componentPath); - $table = $this->components[$componentPath]; + $table = $this->tables[$tableAlias]; if(isset($this->pendingFields[$componentAlias])) { $fields = $this->pendingFields[$componentAlias]; @@ -173,14 +172,12 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { } } public function processPendingAggregates($componentAlias) { - $tableAlias = $this->getTableAlias($componentAlias); - - $componentPath = $this->compAliases[$componentAlias]; + $tableAlias = $this->getTableAlias($componentAlias); - if( ! isset($this->components[$componentPath])) + if( ! isset($this->tables[$tableAlias])) throw new Doctrine_Query_Exception('Unknown component path '.$componentPath); - $table = $this->components[$componentPath]; + $table = $this->tables[$tableAlias]; foreach($this->pendingAggregates[$componentAlias] as $args) { list($name, $arg, $distinct, $alias) = $args; @@ -1145,7 +1142,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { . $assocTableName . '.' . $fk->getLocal(); $this->parts["join"][$tname][$tname2] = $join . $aliasString . ' ON ' . $tname2 . '.' - . $table->getIdentifier() . ' = ' + . $fk->getTable()->getIdentifier() . ' = ' . $assocTableName . '.' . $fk->getForeign(); } else { @@ -1227,14 +1224,14 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $fields = array(); - if(strpos($fullName, "-") === false) { + if(strpos($fullName, '-') === false) { $fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE); 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)); + $fields = explode(',',substr($exploded[1],0,-1)); } } } else { @@ -1244,10 +1241,10 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE); if(isset($exploded[2])) { - if(substr_count($exploded[2], ")") > 1) { + if(substr_count($exploded[2], ')') > 1) { } else { - $fields = explode(",",substr($exploded[2],0,-1)); + $fields = explode(',', substr($exploded[2],0,-1)); } } @@ -1263,27 +1260,27 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @return string */ public function parseAggregateFunction($func,$reference) { - $pos = strpos($func,"("); + $pos = strpos($func, '('); if($pos !== false) { $funcs = array(); $name = substr($func, 0, $pos); $func = substr($func, ($pos + 1), -1); - $params = Doctrine_Query::bracketExplode($func, ",", "(", ")"); + $params = Doctrine_Query::bracketExplode($func, ',', '(', ')'); foreach($params as $k => $param) { $params[$k] = $this->parseAggregateFunction($param,$reference); } - $funcs = $name."(".implode(", ", $params).")"; + $funcs = $name . '(' . implode(', ', $params). ')'; return $funcs; } else { if( ! is_numeric($func)) { - $func = $this->getTableAlias($reference).".".$func; + $func = $this->getTableAlias($reference).'.'.$func; return $func; } else { @@ -1297,7 +1294,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { */ public function parseAggregateValues($fullName, $tableName, array $exploded, $currPath) { $this->aggregate = true; - $pos = strpos($fullName,"("); + $pos = strpos($fullName, '('); $name = substr($fullName, 0, $pos); $string = substr($fullName, ($pos + 1), -1); @@ -1306,7 +1303,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $func = $this->parseAggregateFunction($value, $currPath); $exploded[$k] = $func; - $this->parts["select"][] = $exploded[$k]; + $this->parts['select'][] = $exploded[$k]; } } } diff --git a/lib/Doctrine/Query/Condition.php b/lib/Doctrine/Query/Condition.php index 1da6a23b5..b99a47c19 100644 --- a/lib/Doctrine/Query/Condition.php +++ b/lib/Doctrine/Query/Condition.php @@ -13,33 +13,34 @@ abstract class Doctrine_Query_Condition extends Doctrine_Query_Part { final public function parse($str) { $tmp = trim($str); - $parts = Doctrine_Query::bracketExplode($str, array(' \&\& ', ' AND '), "(", ")"); + $parts = Doctrine_Query::bracketExplode($str, array(' \&\& ', ' AND '), '(', ')'); + if(count($parts) > 1) { $ret = array(); foreach($parts as $part) { - $part = Doctrine_Query::bracketTrim($part, "(", ")"); + $part = Doctrine_Query::bracketTrim($part, '(', ')'); $ret[] = $this->parse($part); } - $r = implode(" AND ",$ret); + $r = implode(' AND ',$ret); } else { - $parts = Doctrine_Query::bracketExplode($str, array(' \|\| ', ' OR '), "(", ")"); + $parts = Doctrine_Query::bracketExplode($str, array(' \|\| ', ' OR '), '(', ')'); if(count($parts) > 1) { $ret = array(); foreach($parts as $part) { - $part = Doctrine_Query::bracketTrim($part, "(", ")"); + $part = Doctrine_Query::bracketTrim($part, '(', ')'); $ret[] = $this->parse($part); } - $r = implode(" OR ",$ret); + $r = implode(' OR ',$ret); } else { - if(substr($parts[0],0,1) == "(" && substr($parts[0],-1) == ")") + if(substr($parts[0],0,1) == '(' && substr($parts[0],-1) == ')') return $this->parse(substr($parts[0],1,-1)); else return $this->load($parts[0]); } } - return "(".$r.")"; + return '(' . $r . ')'; } } diff --git a/manual/documentation.php b/manual/documentation.php index 46d10ee39..0494b1c18 100644 --- a/manual/documentation.php +++ b/manual/documentation.php @@ -327,6 +327,12 @@ $menu = array('Getting started' => 'Planned', 'Technical Details', 'Maintainer'), + 'Hook' => array( + 'Introduction', + 'Building queries', + 'List of parsers', + + ), /** 'Debugger' => array( 'Introduction', diff --git a/tests/ExportReporterTestCase.php b/tests/ExportReporterTestCase.php new file mode 100644 index 000000000..2858798cc --- /dev/null +++ b/tests/ExportReporterTestCase.php @@ -0,0 +1,19 @@ +export->export('BadLyNamed__Class'); + + // Class name is not valid. Double underscores are not allowed + + $this->assertEqual($reporter->pop(), array(E_WARNING, Doctrine::ERR_CLASS_NAME)); + } +} diff --git a/tests/HookTestCase.php b/tests/HookTestCase.php new file mode 100644 index 000000000..f8ee0b9a9 --- /dev/null +++ b/tests/HookTestCase.php @@ -0,0 +1,57 @@ + 'Jack Daniels', + 'u.loginname' => 'TheMan'); + + $hook->hookWhere($a['where']); + $this->assertEqual($hook->getQuery()->getQuery(), 'SELECT e.id AS e__id, e.name AS e__name FROM entity e LEFT JOIN phonenumber p ON e.id = p.entity_id WHERE (e.name LIKE ? OR e.name LIKE ?) AND e.loginname LIKE ? AND (e.type = 0)'); + + } + public function testEqualParserUsesEqualOperator() { + $parser = new Doctrine_Hook_Equal(); + + $parser->parse('u', 'name', 'zYne'); + + $this->assertEqual($parser->getCondition(), 'u.name = ?'); + $this->assertEqual($parser->getParams(), array('zYne')); + } + public function testWordLikeParserUsesLikeOperator() { + $parser = new Doctrine_Hook_WordLike(); + + $parser->parse('u', 'name', 'zYne'); + + $this->assertEqual($parser->getCondition(), 'u.name LIKE ?'); + $this->assertEqual($parser->getParams(), array('zYne%')); + } + public function testIntegerParserSupportsIntervals() { + $parser = new Doctrine_Hook_Integer(); + + $parser->parse('m', 'year', '1998-2000'); + + $this->assertEqual($parser->getCondition(), '(m.year > ? AND m.year < ?)'); + $this->assertEqual($parser->getParams(), array('1998', '2000')); + } + + public function testIntegerParserSupportsEqualOperator() { + $parser = new Doctrine_Hook_Integer(); + + $parser->parse('m', 'year', '1998'); + + $this->assertEqual($parser->getCondition(), 'm.year = ?'); + $this->assertEqual($parser->getParams(), array('1998')); + } + + public function testIntegerParserSupportsNestingConditions() { + $parser = new Doctrine_Hook_Integer(); + + $parser->parse('m', 'year', '1998-2000 OR 2001'); + + $this->assertEqual($parser->getCondition(), '((m.year > ? AND m.year < ?) OR m.year = ?)'); + $this->assertEqual($parser->getParams(), array('1998', '2000', '2001')); + } +} +?> diff --git a/tests/QueryAggregateValueTestCase.php b/tests/QueryAggregateValueTestCase.php new file mode 100644 index 000000000..41d85d9bc --- /dev/null +++ b/tests/QueryAggregateValueTestCase.php @@ -0,0 +1,95 @@ +name = 'John'; + $users[0]->Phonenumber[0]->phonenumber = '123 123'; + $users[0]->Phonenumber[1]->phonenumber = '222 222'; + $users[0]->Phonenumber[2]->phonenumber = '333 333'; + + $users[1]->name = 'John'; + $users[2]->name = 'James'; + $users[2]->Phonenumber[0]->phonenumber = '222 344'; + $users[2]->Phonenumber[1]->phonenumber = '222 344'; + $users[3]->name = 'James'; + $users[3]->Phonenumber[0]->phonenumber = '123 123'; + + $users->save(); + } + public function testRecordSupportsValueMapping() { + $record = new User(); + + try { + $record->get('count'); + $this->fail(); + } catch(Doctrine_Exception $e) { + $this->pass(); + } + + $record->mapValue('count', 3); + + try { + $i = $record->get('count'); + } catch(Doctrine_Exception $e) { + $this->fail(); + } + $this->assertEqual($i, 3); + } + public function testAggregateValueIsMappedToNewRecordOnEmptyResultSet() { + $q = new Doctrine_Query(); + + $q->select('COUNT(u.id) count')->from('User u'); + + $users = $q->execute(); + + $this->assertEqual($users->count(), 1); + $this->assertEqual($users[0]->state(), Doctrine_Record::STATE_TCLEAN); + } + public function testAggregateValueIsMappedToRecord() { + $q = new Doctrine_Query(); + + $q->select('u.name, COUNT(u.id) count')->from('User u')->groupby('u.name'); + + $users = $q->execute(); + + $this->assertEqual($users->count(), 2); + + $this->assertEqual($users[0]->state(), Doctrine_Record::STATE_PROXY); + $this->assertEqual($users[1]->state(), Doctrine_Record::STATE_PROXY); + + $this->assertEqual($users[0]->count, 2); + $this->assertEqual($users[1]->count, 2); + } + public function testAggregateValueMappingSupportsLeftJoins() { + $q = new Doctrine_Query(); + + $q->select('u.name, COUNT(p.id) count')->from('User u')->leftJoin('u.Phonenumber p')->groupby('u.id'); + + $users = $q->execute(); + + $this->assertEqual($users->count(), 4); + + $this->assertEqual($users[0]->Phonenumber[0]->count, 3); + $this->assertEqual($users[1]->Phonenumber[0]->count, 0); + $this->assertEqual($users[2]->Phonenumber[0]->count, 2); + $this->assertEqual($users[3]->Phonenumber[0]->count, 1); + } + public function testAggregateValueMappingSupportsInnerJoins() { + $q = new Doctrine_Query(); + + $q->select('u.name, COUNT(p.id) count')->from('User u')->innerJoin('u.Phonenumber p')->groupby('u.id'); + + $users = $q->execute(); + + $this->assertEqual($users->count(), 3); + + $this->assertEqual($users[0]->Phonenumber[0]->count, 3); + $this->assertEqual($users[1]->Phonenumber[0]->count, 2); + $this->assertEqual($users[2]->Phonenumber[0]->count, 1); + } +} +?> diff --git a/tests/run.php b/tests/run.php index 6f8b5fcc3..6f6bd8210 100644 --- a/tests/run.php +++ b/tests/run.php @@ -29,6 +29,7 @@ require_once('ViewTestCase.php'); require_once('RawSqlTestCase.php'); require_once('CustomPrimaryKeyTestCase.php'); require_once('FilterTestCase.php'); +require_once('HookTestCase.php'); require_once('QueryTestCase.php'); require_once('QueryLimitTestCase.php'); @@ -155,6 +156,7 @@ $test->addTestCase(new Doctrine_Configurable_TestCase()); $test->addTestCase(new Doctrine_Export_Sqlite_TestCase()); */ + $test->addTestCase(new Doctrine_Export_Reporter_TestCase()); $test->addTestCase(new Doctrine_Transaction_TestCase()); @@ -189,7 +191,6 @@ $test->addTestCase(new Doctrine_Db_TestCase()); $test->addTestCase(new Doctrine_Db_Profiler_TestCase()); -$test->addTestCase(new Doctrine_Query_MultiJoin_TestCase()); $test->addTestCase(new Doctrine_Record_TestCase()); @@ -223,7 +224,6 @@ $test->addTestCase(new Doctrine_RawSql_TestCase()); $test->addTestCase(new Doctrine_CollectionTestCase()); -$test->addTestCase(new Doctrine_Query_ReferenceModel_TestCase()); $test->addTestCase(new Doctrine_DataDict_Sqlite_TestCase()); @@ -235,35 +235,26 @@ $test->addTestCase(new Doctrine_CustomResultSetOrderTestCase()); //$test->addTestCase(new Doctrine_Record_Filter_TestCase()); -$test->addTestCase(new Doctrine_Query_Condition_TestCase()); - -$test->addTestCase(new Doctrine_Query_ComponentAlias_TestCase()); - -$test->addTestCase(new Doctrine_Query_Subquery_TestCase()); - $test->addTestCase(new Doctrine_EnumTestCase()); +$test->addTestCase(new Doctrine_Query_MultiJoin_TestCase()); +$test->addTestCase(new Doctrine_Query_ReferenceModel_TestCase()); +$test->addTestCase(new Doctrine_Query_Condition_TestCase()); +$test->addTestCase(new Doctrine_Query_ComponentAlias_TestCase()); +$test->addTestCase(new Doctrine_Query_Subquery_TestCase()); $test->addTestCase(new Doctrine_Query_TestCase()); - $test->addTestCase(new Doctrine_Query_ShortAliases_TestCase()); - $test->addTestCase(new Doctrine_Query_From_TestCase()); - $test->addTestCase(new Doctrine_Query_Delete_TestCase()); - $test->addTestCase(new Doctrine_Query_Where_TestCase()); - $test->addTestCase(new Doctrine_Query_Limit_TestCase()); - $test->addTestCase(new Doctrine_Query_IdentifierQuoting_TestCase()); - $test->addTestCase(new Doctrine_Query_Update_TestCase()); - $test->addTestCase(new Doctrine_Query_AggregateValue_TestCase()); - - $test->addTestCase(new Doctrine_Query_Select_TestCase()); +$test->addTestCase(new Doctrine_Hook_TestCase()); + //$test->addTestCase(new Doctrine_Cache_Query_SqliteTestCase()); //$test->addTestCase(new Doctrine_Cache_FileTestCase()); //$test->addTestCase(new Doctrine_Cache_SqliteTestCase());