From f26217c87acf2eb7fe253d29682d12cb970d0fee Mon Sep 17 00:00:00 2001 From: zYne Date: Wed, 16 May 2007 19:20:55 +0000 Subject: [PATCH] DQL core refactored --- draft/new-core/Query.php | 14 +- draft/new-core/RawSql.php | 54 +- draft/new-core/Table.php | 64 +- lib/Doctrine/Collection.php | 342 ++--- lib/Doctrine/Connection.php | 2 +- lib/Doctrine/Hydrate.php | 571 +++---- lib/Doctrine/Hydrate/Alias.php | 41 +- lib/Doctrine/Lib.php | 23 +- lib/Doctrine/Query.php | 1672 ++++++++------------- lib/Doctrine/Query/Condition.php | 25 +- lib/Doctrine/Query/From.php | 12 +- lib/Doctrine/Query/Groupby.php | 15 +- lib/Doctrine/Query/Having.php | 17 +- lib/Doctrine/Query/JoinCondition.php | 10 +- lib/Doctrine/Query/Limit.php | 41 + lib/Doctrine/Query/Offset.php | 41 + lib/Doctrine/Query/Orderby.php | 17 +- lib/Doctrine/Query/Set.php | 13 +- lib/Doctrine/Query/Where.php | 48 +- lib/Doctrine/Record/Filter.php | 13 +- lib/Doctrine/Relation/Association.php | 2 +- lib/Doctrine/Table.php | 52 +- tests/HydrateTestCase.php | 2 +- tests/Query/AggregateValueTestCase.php | 12 +- tests/Query/DeleteTestCase.php | 20 +- tests/Query/FromTestCase.php | 16 +- tests/Query/HavingTestCase.php | 4 +- tests/Query/IdentifierQuotingTestCase.php | 6 +- tests/Query/JoinConditionTestCase.php | 8 +- tests/Query/JoinTestCase.php | 6 +- tests/Query/LimitTestCase.php | 30 +- tests/Query/OrderbyTestCase.php | 4 +- tests/Query/SelectTestCase.php | 28 +- tests/Query/SubqueryTestCase.php | 8 +- tests/Query/UpdateTestCase.php | 10 +- tests/Query/WhereTestCase.php | 24 +- 36 files changed, 1361 insertions(+), 1906 deletions(-) create mode 100644 lib/Doctrine/Query/Limit.php create mode 100644 lib/Doctrine/Query/Offset.php diff --git a/draft/new-core/Query.php b/draft/new-core/Query.php index 101329653..49535fe53 100644 --- a/draft/new-core/Query.php +++ b/draft/new-core/Query.php @@ -20,7 +20,7 @@ */ Doctrine::autoload('Doctrine_Hydrate'); /** - * Doctrine_Query2 + * Doctrine_Query * * @package Doctrine * @license http://www.opensource.org/licenses/lgpl-license.php LGPL @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Hydrate'); * @version $Revision: 1296 $ * @author Konsta Vesterinen */ -class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable +class Doctrine_Query extends Doctrine_Hydrate2 implements Countable { /** * @param array $subqueryAliases the table aliases needed in some LIMIT subqueries @@ -88,7 +88,7 @@ class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable */ public static function create() { - return new Doctrine_Query2(); + return new Doctrine_Query(); } /** * isSubquery @@ -205,7 +205,7 @@ class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable */ public function parseSelect($dql) { - $refs = Doctrine_Query::bracketExplode($dql, ','); + $refs = Doctrine_Tokenizer::bracketExplode($dql, ','); foreach ($refs as $reference) { if (strpos($reference, '(') !== false) { @@ -237,7 +237,7 @@ class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable */ public function parseSubselect($reference) { - $e = Doctrine_Query::bracketExplode($reference, ' '); + $e = Doctrine_Tokenizer::bracketExplode($reference, ' '); $alias = $e[1]; if (count($e) > 2) { @@ -253,7 +253,7 @@ class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable } public function parseAggregateFunction2($func) { - $e = Doctrine_Query::bracketExplode($func, ' '); + $e = Doctrine_Tokenizer::bracketExplode($func, ' '); $func = $e[0]; $pos = strpos($func, '('); @@ -1132,7 +1132,7 @@ class Doctrine_Query2 extends Doctrine_Hydrate2 implements Countable public function distinct($flag = true) { $this->_parts['distinct'] = (bool) $flag; - + return $this; } diff --git a/draft/new-core/RawSql.php b/draft/new-core/RawSql.php index 054fb6b11..ea16fa38b 100644 --- a/draft/new-core/RawSql.php +++ b/draft/new-core/RawSql.php @@ -87,30 +87,30 @@ class Doctrine_RawSql extends Doctrine_Hydrate foreach ($e as $k => $part) { $low = strtolower($part); switch (strtolower($part)) { - case "select": - case "from": - case "where": - case "limit": - case "offset": - case "having": + case 'select': + case 'from': + case 'where': + case 'limit': + case 'offset': + case 'having': $p = $low; if ( ! isset($parts[$low])) { $parts[$low] = array(); } break; - case "order": - case "group": + case 'order': + case 'group': $i = ($k + 1); - if (isset($e[$i]) && strtolower($e[$i]) === "by") { + if (isset($e[$i]) && strtolower($e[$i]) === 'by') { $p = $low; - $p .= "by"; - $parts[$low."by"] = array(); + $p .= 'by'; + $parts[$low.'by'] = array(); } else { $parts[$p][] = $part; } break; - case "by": + case 'by': continue; default: if ( ! isset($parts[$p][0])) { @@ -118,11 +118,11 @@ class Doctrine_RawSql extends Doctrine_Hydrate } else { $parts[$p][0] .= ' '.$part; } - }; - }; + } + } $this->parts = $parts; - $this->parts["select"] = array(); + $this->parts['select'] = array(); return $this; } @@ -149,12 +149,12 @@ class Doctrine_RawSql extends Doctrine_Hydrate if ($e[1] == '*') { foreach ($this->tables[$e[0]]->getColumnNames() as $name) { - $field = $e[0].".".$name; - $this->parts["select"][$field] = $field." AS ".$e[0]."__".$name; + $field = $e[0] . '.' . $name; + $this->parts['select'][$field] = $field . ' AS ' . $e[0] . '__' . $name; } } else { - $field = $e[0].".".$e[1]; - $this->parts["select"][$field] = $field." AS ".$e[0]."__".$e[1]; + $field = $e[0] . '.' . $e[1]; + $this->parts['select'][$field] = $field . ' AS ' . $e[0] . '__' . $e[1]; } } @@ -163,13 +163,13 @@ class Doctrine_RawSql extends Doctrine_Hydrate foreach ($this->tableAliases as $alias) { foreach ($this->tables[$alias]->getPrimaryKeys() as $key) { $field = $alias . '.' . $key; - if ( ! isset($this->parts["select"][$field])) { - $this->parts["select"][$field] = $field." AS ".$alias."__".$key; + if ( ! isset($this->parts['select'][$field])) { + $this->parts['select'][$field] = $field . ' AS ' . $alias . '__' . $key; } } } - $q = 'SELECT '.implode(', ', $this->parts['select']); + $q = 'SELECT ' . implode(', ', $this->parts['select']); $string = $this->applyInheritance(); if ( ! empty($string)) { @@ -183,8 +183,8 @@ class Doctrine_RawSql extends Doctrine_Hydrate $q .= ( ! empty($this->parts['groupby']))? ' GROUP BY ' . implode(', ', $this->parts['groupby']) : ''; $q .= ( ! empty($this->parts['having']))? ' HAVING ' . implode(' ', $this->parts['having']) : ''; $q .= ( ! empty($this->parts['orderby']))? ' ORDER BY ' . implode(' ', $this->parts['orderby']) : ''; - $q .= ( ! empty($this->parts['limit']))? ' LIMIT ' . implode(' ', $this->parts['limit']) : ''; - $q .= ( ! empty($this->parts['offset']))? ' OFFSET ' . implode(' ', $this->parts['offset']) : ''; + $q .= ( ! empty($this->parts['limit']))? ' LIMIT ' . implode(' ', $this->parts['limit']) : ''; + $q .= ( ! empty($this->parts['offset']))? ' OFFSET ' . implode(' ', $this->parts['offset']) : ''; if ( ! empty($string)) { array_pop($this->parts['where']); @@ -216,8 +216,10 @@ class Doctrine_RawSql extends Doctrine_Hydrate foreach ($e as $k => $component) { $currPath .= '.' . $component; - if ($k == 0) + + if ($k == 0) { $currPath = substr($currPath,1); + } if (isset($this->tableAliases[$currPath])) { $alias = $this->tableAliases[$currPath]; @@ -230,12 +232,12 @@ class Doctrine_RawSql extends Doctrine_Hydrate } $table = $this->conn->getTable($component); $this->tables[$alias] = $table; - $this->fetchModes[$alias] = Doctrine::FETCH_IMMEDIATE; $this->tableAliases[$currPath] = $alias; if ($k !== 0) { $this->joins[$alias] = $prevAlias; } + $prevAlias = $alias; $prevPath = $currPath; } diff --git a/draft/new-core/Table.php b/draft/new-core/Table.php index 5fca1cbe1..7088ef87a 100644 --- a/draft/new-core/Table.php +++ b/draft/new-core/Table.php @@ -19,9 +19,11 @@ * . */ /** - * Doctrine_Table represents a database table - * each Doctrine_Table holds the information of foreignKeys and associations - * + * Doctrine_Table + * + * This class represents a database table. + * Each Doctrine_Table holds the information of foreignKeys and associations + * to other tables. * * @author Konsta Vesterinen * @package Doctrine @@ -54,10 +56,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @var integer $identifierType the type of identifier this table uses */ private $identifierType; - /** - * @var string $query cached simple query - */ - private $query; /** * @var Doctrine_Connection $conn Doctrine_Connection object that created this table */ @@ -150,18 +148,18 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * * -- treeOptions the tree options */ - protected $options = array('name' => null, - 'tableName' => null, - 'sequenceName' => null, - 'inheritanceMap' => array(), - 'enumMap' => array(), - 'engine' => null, - 'charset' => null, - 'collation' => null, - 'treeImpl' => null, - 'treeOptions' => null, - 'indexes' => array(), - ); + protected $options = array('name' => null, + 'tableName' => null, + 'sequenceName' => null, + 'inheritanceMap' => array(), + 'enumMap' => array(), + 'engine' => null, + 'charset' => null, + 'collation' => null, + 'treeImpl' => null, + 'treeOptions' => null, + 'indexes' => array(), + ); /** * @var Doctrine_Tree $tree tree object associated with this table */ @@ -284,19 +282,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $this->identifier = $pk; } } - }; - /** - if ( ! isset($definition['values'])) { - throw new Doctrine_Table_Exception('No values set for enum column ' . $name); - } - - if ( ! is_array($definition['values'])) { - throw new Doctrine_Table_Exception('Enum column values should be specified as an array.'); - } - - */ - - + } } } else { throw new Doctrine_Table_Exception("Class '$name' has no table definition."); @@ -313,9 +299,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable array_pop($names); $this->options['parents'] = $names; - $this->query = 'SELECT ' . implode(', ', array_keys($this->columns)) . ' FROM ' . $this->getTableName(); - - $this->repository = new Doctrine_Table_Repository($this); } /** @@ -1043,7 +1026,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $id = array_values($id); } - $query = $this->query . ' WHERE ' . implode(' = ? AND ', $this->primaryKeys) . ' = ?'; + $query = 'SELECT ' . implode(', ', array_keys($this->columns)) . ' FROM ' . $this->getTableName() . ' WHERE ' . implode(' = ? AND ', $this->primaryKeys) . ' = ?'; $query = $this->applyInheritance($query); $params = array_merge($id, array_values($this->options['inheritanceMap'])); @@ -1430,15 +1413,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $data = $stmt->fetch(PDO::FETCH_NUM); return isset($data[0])?$data[0]:1; } - /** - * returns simple cached query - * - * @return string - */ - final public function getQuery() - { - return $this->query; - } /** * returns internal data, used by Doctrine_Record instances * when retrieving data from database diff --git a/lib/Doctrine/Collection.php b/lib/Doctrine/Collection.php index 533047656..efc1397f0 100644 --- a/lib/Doctrine/Collection.php +++ b/lib/Doctrine/Collection.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload("Doctrine_Access"); +Doctrine::autoload('Doctrine_Access'); /** * Doctrine_Collection * Collection of Doctrine_Record objects. @@ -34,33 +34,29 @@ Doctrine::autoload("Doctrine_Access"); class Doctrine_Collection extends Doctrine_Access implements Countable, IteratorAggregate, Serializable { /** - * @var array $data an array containing the data access objects of this collection + * @var array $data an array containing the records of this collection */ protected $data = array(); /** * @var Doctrine_Table $table each collection has only records of specified table */ - protected $table; + protected $_table; + /** + * @var array $_snapshot a snapshot of the fetched data + */ + protected $_snapshot = array(); /** * @var Doctrine_Record $reference collection can belong to a record */ protected $reference; /** - * @var string $reference_field the reference field of the collection + * @var string $referenceField the reference field of the collection */ - protected $reference_field; + protected $referenceField; /** * @var Doctrine_Relation the record this collection is related to, if any */ protected $relation; - /** - * @var boolean $expandable whether or not this collection has been expanded - */ - protected $expandable = true; - /** - * @var array $expanded - */ - protected $expanded = array(); /** * @var string $keyColumn the name of the column that is used for collection key mapping */ @@ -70,7 +66,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ protected static $null; - protected $aggregateValues = array(); /** * constructor @@ -83,7 +78,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator $table = Doctrine_Manager::getInstance() ->getTable($table); } - $this->table = $table; + $this->_table = $table; $name = $table->getAttribute(Doctrine::ATTR_COLL_KEY); if ($name !== null) { @@ -108,28 +103,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ public function getTable() { - return $this->table; - } - /** - * setAggregateValue - * - * @param string $name - * @param string $value - * @return void - */ - public function setAggregateValue($name, $value) - { - $this->aggregateValues[$name] = $value; - } - /** - * getAggregateValue - * - * @param string $name - * @return mixed - */ - public function getAggregateValue($name) - { - return $this->aggregateValues[$name]; + return $this->_table; } /** * this method is automatically called when this Doctrine_Collection is serialized @@ -168,45 +142,28 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator $this->$name = $values; } - $this->table = $connection->getTable($this->table); + $this->_table = $connection->getTable($this->_table); $this->expanded = array(); $this->expandable = true; - $name = $this->table->getAttribute(Doctrine::ATTR_COLL_KEY); + $name = $this->_table->getAttribute(Doctrine::ATTR_COLL_KEY); if ($name !== null) { $this->keyColumn = $name; } } - /** - * isExpanded - * - * whether or not an offset batch has been expanded - * @return boolean - */ - public function isExpanded($offset) - { - return isset($this->expanded[$offset]); - } - /** - * isExpandable - * - * whether or not this collection is expandable - * @return boolean - */ - public function isExpandable() - { - return $this->expandable; - } /** * setKeyColumn + * sets the key column for this collection * * @param string $column - * @return void + * @return Doctrine_Collection */ public function setKeyColumn($column) { $this->keyColumn = $column; + + return $this; } /** * getKeyColumn @@ -219,6 +176,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator return $this->column; } /** + * getData * returns all the records as an array * * @return array @@ -227,13 +185,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator { return $this->data; } - /** - * @param array $data - */ - public function addData(array $data) - { - $this->data[] = $data; - } /** * getFirst * returns the first record in the collection @@ -269,15 +220,15 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator || $relation instanceof Doctrine_Relation_LocalKey ) { - $this->reference_field = $relation->getForeign(); + $this->referenceField = $relation->getForeign(); $value = $record->get($relation->getLocal()); foreach ($this->getNormalIterator() as $record) { if ($value !== null) { - $record->set($this->reference_field, $value, false); + $record->set($this->referenceField, $value, false); } else { - $record->set($this->reference_field, $this->reference, false); + $record->set($this->referenceField, $this->reference, false); } } } elseif ($relation instanceof Doctrine_Relation_Association) { @@ -293,127 +244,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator { return $this->reference; } - /** - * expand - * expands the collection - * - * @return boolean - */ - public function expand($key) - { - $where = array(); - $params = array(); - $limit = null; - $offset = null; - - switch (get_class($this)) { - case "Doctrine_Collection_Offset": - $limit = $this->getLimit(); - $offset = (floor($key / $limit) * $limit); - - if ( ! $this->expandable && isset($this->expanded[$offset])) { - return false; - } - $fields = implode(", ",$this->table->getColumnNames()); - break; - default: - if ( ! $this->expandable) { - return false; - } - - if ( ! isset($this->reference)) { - return false; - } - - $id = $this->reference->obtainIdentifier(); - - if (empty($id)) { - return false; - } - - switch (get_class($this)) { - case "Doctrine_Collection_Immediate": - $fields = implode(", ",$this->table->getColumnNames()); - break; - default: - $fields = implode(", ",$this->table->getPrimaryKeys()); - }; - }; - - if (isset($this->relation)) { - if ($this->relation instanceof Doctrine_Relation_ForeignKey) { - $params[] = $this->reference->getIncremented(); - $where[] = $this->reference_field." = ?"; - - if ( ! isset($offset)) { - $ids = $this->getPrimaryKeys(); - - if ( ! empty($ids)) { - $where[] = $this->table->getIdentifier()." NOT IN (".substr(str_repeat("?, ",count($ids)),0,-2).")"; - $params = array_merge($params,$ids); - } - - $this->expandable = false; - } - - } elseif ($this->relation instanceof Doctrine_Relation_Association) { - - $asf = $this->relation->getAssociationFactory(); - $query = 'SELECT '.$foreign." FROM ".$asf->getTableName()." WHERE ".$local."=".$this->getIncremented(); - - $table = $fk->getTable(); - $graph = new Doctrine_Query($table->getConnection()); - - $q = 'FROM ' . $table->getComponentName() . ' WHERE ' . $table->getComponentName() . '.' . $table->getIdentifier()." IN ($query)"; - - } - } - - $query = "SELECT ".$fields." FROM ".$this->table->getTableName(); - - // apply column aggregation inheritance - $map = $this->table->inheritanceMap; - foreach ($map as $k => $v) { - $where[] = $k." = ?"; - $params[] = $v; - } - if ( ! empty($where)) { - $query .= " WHERE ".implode(" AND ",$where); - } - - $coll = $this->table->execute($query, $params, $limit, $offset); - - if ( ! isset($offset)) { - foreach ($coll as $record) { - if (isset($this->reference_field)) { - $record->set($this->reference_field,$this->reference, false); - } - $this->reference->addReference($record, $this->relation); - } - } else { - $i = $offset; - - foreach ($coll as $record) { - if (isset($this->reference)) { - $this->reference->addReference($record, $this->relation, $i); - } else { - $this->data[$i] = $record; - } - $i++; - } - - $this->expanded[$offset] = true; - - // check if the fetched collection's record count is smaller - // than the query limit, if so this collection has been expanded to its max size - - if (count($coll) < $limit) { - $this->expandable = false; - } - } - - return $coll; - } /** * remove * removes a specified collection element @@ -464,11 +294,11 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ public function get($key) { - if ($key === null) { - $record = $this->table->create(); + if ($key === null || ! isset($this->data[$key])) { + $record = $this->_table->create(); - if (isset($this->reference_field)) { - $record->set($this->reference_field, $this->reference, false); + if (isset($this->referenceField)) { + $record->set($this->referenceField, $this->reference, false); } $this->data[] = $record; @@ -476,25 +306,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator return $record; } - - if ( ! isset($this->data[$key])) { - $this->expand($key); - - if ( ! isset($this->data[$key])) { - $this->data[$key] = $this->table->create(); - } - if (isset($this->reference_field)) { - $value = $this->reference->get($this->relation->getLocal()); - - if ($value !== null) { - $this->data[$key]->set($this->reference_field, $value, false); - } else { - - $this->data[$key]->set($this->reference_field, $this->reference, false); - } - } - } - return $this->data[$key]; } @@ -504,7 +315,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator public function getPrimaryKeys() { $list = array(); - $name = $this->table->getIdentifier(); + $name = $this->_table->getIdentifier(); foreach ($this->data as $record) { if (is_array($record) && isset($record[$name])) { @@ -512,7 +323,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator } else { $list[] = $record->getIncremented(); } - }; + } return $list; } /** @@ -542,8 +353,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ public function set($key, Doctrine_Record $record) { - if (isset($this->reference_field)) { - $record->set($this->reference_field, $this->reference, false); + if (isset($this->referenceField)) { + $record->set($this->referenceField, $this->reference, false); } $this->data[$key] = $record; } @@ -553,10 +364,10 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator * @param string $key optional key for the record * @return boolean */ - public function add(Doctrine_Record $record,$key = null) + public function add(Doctrine_Record $record, $key = null) { - if (isset($this->reference_field)) { - $record->set($this->reference_field, $this->reference, false); + if (isset($this->referenceField)) { + $record->set($this->referenceField, $this->reference, false); } /** * for some weird reason in_array cannot be used here (php bug ?) @@ -597,7 +408,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator public function loadRelated($name = null) { $list = array(); - $query = new Doctrine_Query($this->table->getConnection()); + $query = new Doctrine_Query($this->_table->getConnection()); if ( ! isset($name)) { foreach ($this->data as $record) { @@ -606,13 +417,13 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator $list[] = $value; } }; - $query->from($this->table->getComponentName() . '(' . implode(", ",$this->table->getPrimaryKeys()) . ')'); - $query->where($this->table->getComponentName() . '.id IN (' . substr(str_repeat("?, ", count($list)),0,-2) . ')'); + $query->from($this->_table->getComponentName() . '(' . implode(", ",$this->_table->getPrimaryKeys()) . ')'); + $query->where($this->_table->getComponentName() . '.id IN (' . substr(str_repeat("?, ", count($list)),0,-2) . ')'); return $query; } - $rel = $this->table->getRelation($name); + $rel = $this->_table->getRelation($name); if ($rel instanceof Doctrine_Relation_LocalKey || $rel instanceof Doctrine_Relation_ForeignKey) { foreach ($this->data as $record) { @@ -642,7 +453,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ public function populateRelated($name, Doctrine_Collection $coll) { - $rel = $this->table->getRelation($name); + $rel = $this->_table->getRelation($name); $table = $rel->getTable(); $foreign = $rel->getForeign(); $local = $rel->getLocal(); @@ -657,9 +468,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator } } elseif ($rel instanceof Doctrine_Relation_ForeignKey) { foreach ($this->data as $key => $record) { - if ($record->state() == Doctrine_Record::STATE_TCLEAN - || $record->state() == Doctrine_Record::STATE_TDIRTY - ) { + if ( ! $record->exists()) { continue; } $sub = new Doctrine_Collection($table); @@ -674,14 +483,12 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator $this->data[$key]->setRelated($name, $sub); } } elseif ($rel instanceof Doctrine_Relation_Association) { - $identifier = $this->table->getIdentifier(); + $identifier = $this->_table->getIdentifier(); $asf = $rel->getAssociationFactory(); $name = $table->getComponentName(); foreach ($this->data as $key => $record) { - if ($record->state() == Doctrine_Record::STATE_TCLEAN - || $record->state() == Doctrine_Record::STATE_TDIRTY - ) { + if ( ! $record->exists()) { continue; } $sub = new Doctrine_Collection($table); @@ -705,36 +512,93 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator { return new Doctrine_Collection_Iterator_Normal($this); } + /** + * takeSnapshot + * takes a snapshot from this collection + * + * snapshots are used for diff processing, for example + * when a fetched collection has three elements, then two of those + * are being removed the diff would contain one element + * + * Doctrine_Collection::save() attaches the diff with the help of last + * snapshot. + * + * @return Doctrine_Collection + */ + public function takeSnapshot() + { + $this->_snapshot = $this->data; + + return $this; + } + /** + * getSnapshot + * returns the data of the last snapshot + * + * @return array returns the data in last snapshot + */ + public function getSnapshot() + { + return $this->_snapshot; + } + /** + * processDiff + * processes the difference of the last snapshot and the current data + * + * an example: + * Snapshot with the objects 1, 2 and 4 + * Current data with objects 2, 3 and 5 + * + * The process would: + * 1. remove object 4 + * 2. add objects 3 and 5 + * + * @return Doctrine_Collection + */ + public function processDiff() + { + foreach (array_diff($this->snapshot, $this->data) as $record) { + $record->delete(); + } + foreach (array_diff($this->data, $this->snapshot) as $record) { + $record->save(); + } + + return $this; + } /** * save * saves all records of this collection * - * @return void + * @return Doctrine_Collection */ public function save(Doctrine_Connection $conn = null) { if ($conn == null) { - $conn = $this->table->getConnection(); + $conn = $this->_table->getConnection(); } $conn->beginTransaction(); foreach ($this as $key => $record) { $record->save($conn); - }; + } $conn->commit(); + + return $this; } /** + * delete * single shot delete * deletes all records from this collection * and uses only one database query to perform this operation * - * @return boolean + * @return Doctrine_Collection */ public function delete(Doctrine_Connection $conn = null) { if ($conn == null) { - $conn = $this->table->getConnection(); + $conn = $this->_table->getConnection(); } $conn->beginTransaction(); @@ -746,6 +610,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator $conn->commit(); $this->data = array(); + + return $this; } /** * getIterator diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 92d91e0f3..4bb341690 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -999,7 +999,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun case Doctrine_Record::STATE_TCLEAN: // do nothing break; - }; + } $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record); } diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index fabae7804..d4561300b 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Access'); + /** * Doctrine_Hydrate is a base class for Doctrine_RawSql and Doctrine_Query. * Its purpose is to populate object graphs. @@ -32,7 +32,7 @@ Doctrine::autoload('Doctrine_Access'); * @version $Revision$ * @author Konsta Vesterinen */ -abstract class Doctrine_Hydrate extends Doctrine_Access +class Doctrine_Hydrate { /** * QUERY TYPE CONSTANTS @@ -58,23 +58,7 @@ abstract class Doctrine_Hydrate extends Doctrine_Access * constant for CREATE queries */ const CREATE = 4; - /** - * @var array $fetchmodes an array containing all fetchmodes - */ - protected $fetchModes = array(); - /** - * @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 hydrater has created/will create - */ - protected $collections = array(); - /** - * @var array $joins an array containing all table joins - */ - protected $joins = array(); + /** * @var array $params query input parameters */ @@ -88,28 +72,28 @@ abstract class Doctrine_Hydrate extends Doctrine_Access */ protected $view; /** - * @var boolean $inheritanceApplied + * @var array $_aliasMap two dimensional array containing the map for query aliases + * Main keys are component aliases + * + * table table object associated with given alias + * + * relation the relation object owned by the parent + * + * parent the alias of the parent */ - protected $inheritanceApplied = false; - /** - * @var boolean $aggregate - */ - protected $aggregate = false; - /** - * @var array $compAliases - */ - protected $compAliases = array(); + protected $_aliasMap = array(); + /** * @var array $tableAliases */ protected $tableAliases = array(); /** - * @var array $tableIndexes + * */ - protected $tableIndexes = array(); - protected $pendingAggregates = array(); - + /** + * + */ protected $subqueryAggregates = array(); /** * @var array $aggregateMap an array containing all aggregate aliases, keys as dql aliases @@ -154,15 +138,6 @@ abstract class Doctrine_Hydrate extends Doctrine_Access $this->conn = $connection; $this->aliasHandler = new Doctrine_Hydrate_Alias(); } - /** - * getComponentAliases - * - * @return array - */ - public function getComponentAliases() - { - return $this->compAliases; - } /** * getTableAliases * @@ -172,47 +147,52 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { return $this->tableAliases; } - /** - * getTableIndexes - * - * @return array - */ - public function getTableIndexes() + public function setTableAliases(array $aliases) { - return $this->tableIndexes; + $this->tableAliases = $aliases; } - /** - * getTables - * - * @return array - */ - public function getTables() + public function getTableAlias($componentAlias) { - return $this->tables; + return $this->aliasHandler->getShortAlias($componentAlias); + } + public function addQueryPart($name, $part) + { + if ( ! isset($this->parts[$name])) { + throw new Doctrine_Hydrate_Exception('Unknown query part ' . $name); + } + $this->parts[$name][] = $part; + } + public function getDeclaration($name) + { + if ( ! isset($this->_aliasMap[$name])) { + throw new Doctrine_Hydrate_Exception('Unknown component alias ' . $name); + } + + return $this->_aliasMap[$name]; + } + public function setQueryPart($name, $part) + { + if ( ! isset($this->parts[$name])) { + throw new Doctrine_Hydrate_Exception('Unknown query part ' . $name); + } + + if ($name !== 'limit' && $name !== 'offset') { + $this->parts[$name] = array($part); + } else { + $this->parts[$name] = $part; + } } /** * copyAliases * * @return void */ - public function copyAliases(Doctrine_Hydrate $query) + public function copyAliases($query) { - $this->compAliases = $query->getComponentAliases(); - $this->tableAliases = $query->getTableAliases(); - $this->tableIndexes = $query->getTableIndexes(); $this->aliasHandler = $query->aliasHandler; return $this; } - - public function getPathAlias($path) - { - $s = array_search($path, $this->compAliases); - if ($s === false) - return $path; - - return $s; - } /** * createSubquery * @@ -231,12 +211,6 @@ abstract class Doctrine_Hydrate extends Doctrine_Access return $obj; } - /** - * getQuery - * - * @return string - */ - abstract public function getQuery(); /** * limitSubqueryUsed * @@ -246,7 +220,14 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { return false; } + public function getQueryPart($part) + { + if ( ! isset($this->parts[$part])) { + throw new Doctrine_Hydrate_Exception('Unknown query part ' . $part); + } + return $this->parts[$part]; + } /** * remove * @@ -271,25 +252,20 @@ abstract class Doctrine_Hydrate extends Doctrine_Access */ protected function clear() { - $this->fetchModes = array(); $this->tables = array(); $this->parts = array( - "select" => array(), - "from" => array(), - "join" => array(), - "where" => array(), - "groupby" => array(), - "having" => array(), - "orderby" => array(), - "limit" => false, - "offset" => false, - ); + 'select' => array(), + 'from' => array(), + 'set' => array(), + 'join' => array(), + 'where' => array(), + 'groupby' => array(), + 'having' => array(), + 'orderby' => array(), + 'limit' => false, + 'offset' => false, + ); $this->inheritanceApplied = false; - $this->aggregate = false; - - $this->collections = array(); - $this->joins = array(); - $this->tableIndexes = array(); $this->tableAliases = array(); $this->aliasHandler->clear(); } @@ -333,56 +309,6 @@ abstract class Doctrine_Hydrate extends Doctrine_Access { return $this->params; } - /** - * getTableAlias - * - * @param string $path - * @return string - */ - final public function getTableAlias($path) - { - if (isset($this->compAliases[$path])) { - $path = $this->compAliases[$path]; - } - if ( ! isset($this->tableAliases[$path])) { - return false; - } - return $this->tableAliases[$path]; - } - /** - * getCollection - * - * @parma string $name component name - * @param integer $index - */ - private function getCollection($name) - { - $table = $this->tables[$name]; - if ( ! isset($this->fetchModes[$name])) { - return new Doctrine_Collection($table); - } - switch ($this->fetchModes[$name]) { - case Doctrine::FETCH_BATCH: - $coll = new Doctrine_Collection_Batch($table); - break; - case Doctrine::FETCH_LAZY: - $coll = new Doctrine_Collection_Lazy($table); - break; - case Doctrine::FETCH_OFFSET: - $coll = new Doctrine_Collection_Offset($table); - break; - case Doctrine::FETCH_IMMEDIATE: - $coll = new Doctrine_Collection_Immediate($table); - break; - case Doctrine::FETCH_LAZY_OFFSET: - $coll = new Doctrine_Collection_LazyOffset($table); - break; - default: - throw new Doctrine_Exception("Unknown fetchmode"); - }; - - return $coll; - } /** * setParams * @@ -392,15 +318,14 @@ abstract class Doctrine_Hydrate extends Doctrine_Access $this->params = $params; } /** - * execute - * executes the dql query and populates all collections + * _fetch * - * @param string $params - * @return Doctrine_Collection the root collection + * @param array $params prepared statement parameters + * @param integer $fetchMode the fetchmode + * @see Doctrine::FETCH_* constants */ - public function execute($params = array(), $return = Doctrine::FETCH_RECORD) { - $this->collections = array(); - + public function _fetch($params = array(), $fetchMode = Doctrine::FETCH_RECORD) + { $params = $this->conn->convertBooleans(array_merge($this->params, $params)); if ( ! $this->view) { @@ -409,246 +334,188 @@ abstract class Doctrine_Hydrate extends Doctrine_Access $query = $this->view->getSelectSql(); } - if ($this->isLimitSubqueryUsed() && + if ($this->isLimitSubqueryUsed() && $this->conn->getDBH()->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') { $params = array_merge($params, $params); } $stmt = $this->conn->execute($query, $params); - if ($this->aggregate) { - return $stmt->fetchAll(Doctrine::FETCH_ASSOC); + return $this->parseData($stmt); + } + + public function setAliasMap($map) + { + $this->_aliasMap = $map; + } + public function getAliasMap() + { + return $this->_aliasMap; + } + /** + * mapAggregateValues + * map the aggregate values of given dataset row to a given record + * + * @param Doctrine_Record $record + * @param array $row + * @return Doctrine_Record + */ + public function mapAggregateValues($record, array $row, $alias) + { + $found = false; + // aggregate values have numeric keys + if (isset($row[0])) { + // map each aggregate value + foreach ($row as $index => $value) { + $agg = false; + + if (isset($this->pendingAggregates[$alias][$index])) { + $agg = $this->pendingAggregates[$alias][$index][3]; + } elseif (isset($this->subqueryAggregates[$alias][$index])) { + $agg = $this->subqueryAggregates[$alias][$index]; + } + $record->mapValue($agg, $value); + $found = true; + } } + return $found; + } + /** + * execute + * executes the dql query and populates all collections + * + * @param string $params + * @return Doctrine_Collection the root collection + */ + public function execute($params = array(), $return = Doctrine::FETCH_RECORD) + { + $array = (array) $this->_fetch($params, $return = Doctrine::FETCH_RECORD); - if (count($this->tables) == 0) { - throw new Doctrine_Query_Exception('No components selected'); - } - - $keys = array_keys($this->tables); - $root = $keys[0]; - - $previd = array(); - - $coll = $this->getCollection($root); - $prev[$root] = $coll; - - if ($this->aggregate) { - $return = Doctrine::FETCH_ARRAY; - } - - $array = $this->parseData($stmt); - - if ($return == Doctrine::FETCH_ARRAY) { - return $array; + if (empty($this->_aliasMap)) { + throw new Doctrine_Hydrate_Exception("Couldn't execute query. Component alias map was empty."); } + // initialize some variables used within the main loop + reset($this->_aliasMap); + $rootMap = current($this->_aliasMap); + $rootAlias = key($this->_aliasMap); + $coll = new Doctrine_Collection2($rootMap['table']); + $prev[$rootAlias] = $coll; + $prevRow = array(); + /** + * iterate over the fetched data + * here $data is a two dimensional array + */ foreach ($array as $data) { /** * remove duplicated data rows and map data into objects */ - foreach ($data as $key => $row) { + foreach ($data as $tableAlias => $row) { + // skip empty rows (not mappable) if (empty($row)) { continue; } - //$key = array_search($key, $this->shortAliases); + $alias = $this->aliasHandler->getComponentAlias($tableAlias); + $map = $this->_aliasMap[$alias]; - foreach ($this->tables as $k => $t) { - if ( ! strcasecmp($key, $k)) { - $key = $k; - } + // initialize previous row array if not set + if ( ! isset($prevRow[$tableAlias])) { + $prevRow[$tableAlias] = array(); } - if ( !isset($this->tables[$key]) ) { - throw new Doctrine_Exception('No table named ' . $key . ' found.'); - } - $ids = $this->tables[$key]->getIdentifier(); - $name = $key; + // don't map duplicate rows + if ($prevRow[$tableAlias] !== $row) { + $identifiable = $this->isIdentifiable($row, $map['table']->getIdentifier()); - if ($this->isIdentifiable($row, $ids)) { - if ($name !== $root) { - $prev = $this->initRelated($prev, $name); + if ($identifiable) { + // set internal data + $map['table']->setData($row); } - // aggregate values have numeric keys - if (isset($row[0])) { - $component = $this->tables[$name]->getComponentName(); - - // if the collection already has objects, get the last object - // otherwise create a new one where the aggregate values are being mapped - - if ($prev[$name]->count() > 0) { - $record = $prev[$name]->getLast(); - } else { - $record = new $component(); - $prev[$name]->add($record); - } - - $path = array_search($name, $this->tableAliases); - $alias = $this->getPathAlias($path); - - // map each aggregate value - foreach ($row as $index => $value) { - $agg = false; - - if (isset($this->pendingAggregates[$alias][$index])) { - $agg = $this->pendingAggregates[$alias][$index][3]; - } elseif (isset($this->subqueryAggregates[$alias][$index])) { - $agg = $this->subqueryAggregates[$alias][$index]; - } - - $record->mapValue($agg, $value); - } - } - - continue; - - } - - if ( ! isset($previd[$name])) { - $previd[$name] = array(); - } - if ($previd[$name] !== $row) { - // set internal data - - $this->tables[$name]->setData($row); // initialize a new record + $record = $map['table']->getRecord(); - $record = $this->tables[$name]->getRecord(); - - // aggregate values have numeric keys - if (isset($row[0])) { - $path = array_search($name, $this->tableAliases); - $alias = $this->getPathAlias($path); - - // map each aggregate value - foreach ($row as $index => $value) { - $agg = false; - - if (isset($this->pendingAggregates[$alias][$index])) { - $agg = $this->pendingAggregates[$alias][$index][3]; - } elseif (isset($this->subqueryAggregates[$alias][$index])) { - $agg = $this->subqueryAggregates[$alias][$index]; - } - $record->mapValue($agg, $value); - } + // map aggregate values (if any) + if($this->mapAggregateValues($record, $row, $alias)) { + $identifiable = true; } - if ($name == $root) { + + if ($alias == $rootAlias) { // add record into root collection - - $coll->add($record); - unset($previd); - + + if ($identifiable) { + $coll->add($record); + unset($prevRow); + } } else { - $prev = $this->addRelated($prev, $name, $record); - } + $relation = $map['relation']; + $parentAlias = $map['parent']; + $parentMap = $this->_aliasMap[$parentAlias]; + $parent = $prev[$parentAlias]->getLast(); + + // check the type of the relation + if ($relation->isOneToOne()) { + if ( ! $identifiable) { + continue; + } + $prev[$alias] = $record; + } else { + // one-to-many relation or many-to-many relation + if ( ! $prev[$parentAlias]->getLast()->hasReference($relation->getAlias())) { + // initialize a new collection + $prev[$alias] = new Doctrine_Collection($map['table']); + $prev[$alias]->setReference($parent, $relation); + } else { + // previous entry found from memory + $prev[$alias] = $prev[$parentAlias]->getLast()->get($relation->getAlias()); + } + // add record to the current collection + if ($identifiable) { + $prev[$alias]->add($record); + } + } + // initialize the relation from parent to the current collection/record + $parent->set($relation->getAlias(), $prev[$alias]); + } + // following statement is needed to ensure that mappings // are being done properly when the result set doesn't // contain the rows in 'right order' - - if ($prev[$name] !== $record) { - $prev[$name] = $record; + + if ($prev[$alias] !== $record) { + $prev[$alias] = $record; } } - - $previd[$name] = $row; + $prevRow[$tableAlias] = $row; } } - return $coll; } - /** - * initRelation - * - * @param array $prev - * @param string $name - * @return array - */ - public function initRelated(array $prev, $name) - { - $pointer = $this->joins[$name]; - $path = array_search($name, $this->tableAliases); - $tmp = explode('.', $path); - $alias = end($tmp); - - if ( ! isset($prev[$pointer]) ) { - return $prev; - } - $fk = $this->tables[$pointer]->getRelation($alias); - - if ( ! $fk->isOneToOne()) { - if ($prev[$pointer]->getLast() instanceof Doctrine_Record) { - if ( ! $prev[$pointer]->getLast()->hasReference($alias)) { - $prev[$name] = $this->getCollection($name); - $prev[$pointer]->getLast()->initReference($prev[$name],$fk); - } else { - $prev[$name] = $prev[$pointer]->getLast()->get($alias); - } - } - } - - return $prev; - } - /** - * addRelated - * - * @param array $prev - * @param string $name - * @return array - */ - public function addRelated(array $prev, $name, Doctrine_Record $record) - { - $pointer = $this->joins[$name]; - - $path = array_search($name, $this->tableAliases); - $tmp = explode('.', $path); - $alias = end($tmp); - - $fk = $this->tables[$pointer]->getRelation($alias); - - if ($fk->isOneToOne()) { - $prev[$pointer]->getLast()->set($fk->getAlias(), $record); - - $prev[$name] = $record; - } else { - // one-to-many relation or many-to-many relation - - if ( ! $prev[$pointer]->getLast()->hasReference($alias)) { - $prev[$name] = $this->getCollection($name); - $prev[$pointer]->getLast()->initReference($prev[$name], $fk); - - } else { - // previous entry found from memory - $prev[$name] = $prev[$pointer]->getLast()->get($alias); - } - - $prev[$pointer]->getLast()->addReference($record, $fk); - } - return $prev; - } /** * isIdentifiable * returns whether or not a given data row is identifiable (it contains - * all id fields specified in the second argument) + * all primary key fields specified in the second argument) * * @param array $row - * @param mixed $ids + * @param mixed $primaryKeys * @return boolean */ - public function isIdentifiable(array $row, $ids) + public function isIdentifiable(array $row, $primaryKeys) { - if (is_array($ids)) { - foreach ($ids as $id) { - if ($row[$id] == null) - return true; + if (is_array($primaryKeys)) { + foreach ($primaryKeys as $id) { + if ($row[$id] == null) { + return false; + } } } else { - if ( ! isset($row[$ids])) { - return true; + if ( ! isset($row[$primaryKeys])) { + return false; } } - return false; + return true; } /** * getType @@ -679,12 +546,13 @@ abstract class Doctrine_Hydrate extends Doctrine_Access // get the inheritance maps $array = array(); - foreach ($this->tables as $alias => $table) { - $array[$alias][] = $table->inheritanceMap; + foreach ($this->_aliasMap as $componentAlias => $data) { + $tableAlias = $this->getTableAlias($componentAlias); + $array[$tableAlias][] = $data['table']->inheritanceMap; } // apply inheritance maps - $str = ""; + $str = ''; $c = array(); $index = 0; @@ -742,32 +610,19 @@ abstract class Doctrine_Hydrate extends Doctrine_Access foreach ($data as $key => $value) { $e = explode('__', $key); - $field = strtolower(array_pop($e)); - $component = strtolower(implode('__', $e)); + $field = strtolower(array_pop($e)); + $tableAlias = strtolower(implode('__', $e)); - $data[$component][$field] = $value; + $data[$tableAlias][$field] = $value; unset($data[$key]); - }; + } $array[] = $data; - }; + } $stmt->closeCursor(); return $array; } - /** - * returns a Doctrine_Table for given name - * - * @param string $name component name - * @return Doctrine_Table|boolean - */ - public function getTable($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/Hydrate/Alias.php b/lib/Doctrine/Hydrate/Alias.php index df0e3c7cb..ec1f2f741 100644 --- a/lib/Doctrine/Hydrate/Alias.php +++ b/lib/Doctrine/Hydrate/Alias.php @@ -50,8 +50,9 @@ class Doctrine_Hydrate_Alias $name = substr($alias, 0, 1); $i = ((int) substr($alias, 1)); - if ($i == 0) + if ($i == 0) { $i = 1; + } $newIndex = ($this->shortAliasIndexes[$name] + $i); @@ -65,6 +66,15 @@ class Doctrine_Hydrate_Alias { return (isset($this->shortAliases[$tableName])); } + + public function getComponentAlias($tableAlias) + { + if ( ! isset($this->shortAliases[$tableAlias])) { + throw new Doctrine_Hydrate_Exception('Unknown table alias ' . $tableAlias); + } + return $this->shortAliases[$tableAlias]; + } + public function getShortAliasIndex($alias) { if ( ! isset($this->shortAliasIndexes[$alias])) { @@ -72,7 +82,7 @@ class Doctrine_Hydrate_Alias } return $this->shortAliasIndexes[$alias]; } - public function generateShortAlias($tableName) + public function generateShortAlias($componentAlias, $tableName) { $char = strtolower(substr($tableName, 0, 1)); @@ -84,18 +94,35 @@ class Doctrine_Hydrate_Alias while (isset($this->shortAliases[$alias])) { $alias = $char . ++$this->shortAliasIndexes[$alias]; } - $this->shortAliases[$alias] = $tableName; + + $this->shortAliases[$alias] = $componentAlias; return $alias; } - - public function getShortAlias($tableName) + /** + * getShortAlias + * some database such as Oracle need the identifier lengths to be < ~30 chars + * hence Doctrine creates as short identifier aliases as possible + * + * this method is used for the creation of short table aliases, its also + * smart enough to check if an alias already exists for given component (componentAlias) + * + * @param string $componentAlias the alias for the query component to search table alias for + * @param string $tableName the table name from which the table alias is being created + * @return string the generated / fetched short alias + */ + public function getShortAlias($componentAlias, $tableName = null) { - $alias = array_search($tableName, $this->shortAliases); + $alias = array_search($componentAlias, $this->shortAliases); if ($alias !== false) { return $alias; } - return $this->generateShortAlias($tableName); + + if ($tableName === null) { + throw new Doctrine_Hydrate_Exception("Couldn't get short alias for " . $componentAlias); + } + + return $this->generateShortAlias($componentAlias, $tableName); } } diff --git a/lib/Doctrine/Lib.php b/lib/Doctrine/Lib.php index 3835ce62c..a45253cbb 100644 --- a/lib/Doctrine/Lib.php +++ b/lib/Doctrine/Lib.php @@ -63,13 +63,14 @@ class Doctrine_Lib */ public static function getRecordAsString(Doctrine_Record $record) { - $r[] = "
";
-        $r[] = "Component  : ".$record->getTable()->getComponentName();
-        $r[] = "ID         : ".$record->obtainIdentifier();
-        $r[] = "References : ".count($record->getReferences());
-        $r[] = "State      : ".Doctrine_Lib::getRecordStateAsString($record->getState());
-        $r[] = "OID        : ".$record->getOID();
-        $r[] = "
"; + $r[] = '
';
+        $r[] = 'Component  : ' . $record->getTable()->getComponentName();
+        $r[] = 'ID         : ' . $record->obtainIdentifier();
+        $r[] = 'References : ' . count($record->getReferences());
+        $r[] = 'State      : ' . Doctrine_Lib::getRecordStateAsString($record->getState());
+        $r[] = 'OID        : ' . $record->getOID();
+        $r[] = 'data       : ' . Doctrine::dump($record->getData(), false);
+        $r[] = '
'; return implode("\n",$r)."
"; } /** @@ -84,12 +85,12 @@ class Doctrine_Lib public static function getCollectionAsXml(Doctrine_Collection $collection, SimpleXMLElement $incomming_xml = null){ - $collection_name = Doctrine_Lib::plurelize($collection->getTable()->name); + $collectionName = Doctrine_Lib::plurelize($collection->getTable()->name); - if (!isset($incomming_xml)) { - $xml = new SimpleXMLElement("<" . $collection_name . ">"); + if ( ! isset($incomming_xml)) { + $xml = new SimpleXMLElement("<" . $collectionName . ">"); } else { - $xml = $incomming_xml->addChild($collection_name); + $xml = $incomming_xml->addChild($collectionName); } foreach ($collection as $key => $record) { Doctrine_Lib::getRecordAsXml($record, $xml); diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 218650a0f..070dd9b03 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -30,7 +30,8 @@ Doctrine::autoload('Doctrine_Hydrate'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Query extends Doctrine_Hydrate implements Countable { +class Doctrine_Query extends Doctrine_Hydrate2 implements Countable +{ /** * @param array $subqueryAliases the table aliases needed in some LIMIT subqueries */ @@ -43,20 +44,17 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @param boolean $limitSubqueryUsed */ private $limitSubqueryUsed = false; + + + protected $_status = array('needsSubquery' => true); /** * @param boolean $isSubquery whether or not this query object is a subquery of another * query object */ private $isSubquery; - private $tableStack; - - private $relationStack = array(); - private $isDistinct = false; - - protected $components = array(); - + private $neededTables = array(); /** * @var array $pendingFields @@ -71,9 +69,15 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @var boolean $subqueriesProcessed Whether or not pending subqueries have already been processed. * Consequent calls to getQuery would result badly constructed queries * without this variable + * + * Since subqueries can be correlated, they can only be processed when + * the main query is fully constructed */ private $subqueriesProcessed = false; - + /** + * @var array $_parsers an array of parser objects + */ + protected $_parsers = array(); /** @@ -123,16 +127,6 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return null; } - public function getTableStack() - { - return $this->tableStack; - } - - public function getRelationStack() - { - return $this->relationStack; - } - public function isDistinct($distinct = null) { if(isset($distinct)) @@ -141,18 +135,48 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return $this->isDistinct; } + /** + * getParser + * parser lazy-loader + * + * @throws Doctrine_Query_Exception if unknown parser name given + * @return Doctrine_Query_Part + */ + public function getParser($name) + { + if ( ! isset($this->_parsers[$name])) { + $class = 'Doctrine_Query_' . ucwords(strtolower($name)); + + Doctrine::autoload($class); + + if ( ! class_exists($class)) { + throw new Doctrine_Query_Exception('Unknown parser ' . $name); + } + + $this->_parsers[$name] = new $class($this); + } + + return $this->_parsers[$name]; + } + /** + * processPendingFields + * the fields in SELECT clause cannot be parsed until the components + * in FROM clause are parsed, hence this method is called everytime a + * specific component is being parsed. + * + * @throws Doctrine_Query_Exception if unknown component alias has been given + * @param string $componentAlias the alias of the component + * @return void + */ public function processPendingFields($componentAlias) { $tableAlias = $this->getTableAlias($componentAlias); - - if ( ! isset($this->tables[$tableAlias])) - throw new Doctrine_Query_Exception('Unknown component path '.$componentAlias); - - $table = $this->tables[$tableAlias]; + $table = $this->_aliasMap[$componentAlias]['table']; if (isset($this->pendingFields[$componentAlias])) { $fields = $this->pendingFields[$componentAlias]; + // check for wildcards if (in_array('*', $fields)) { $fields = $table->getColumnNames(); } else { @@ -251,9 +275,10 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $e2 = explode(' ', $args[0]); $distinct = ''; - if(count($e2) > 1) { - if(strtoupper($e2[0]) == 'DISTINCT') + if (count($e2) > 1) { + if (strtoupper($e2[0]) == 'DISTINCT') { $distinct = 'DISTINCT '; + } $args[0] = $e2[1]; } @@ -266,7 +291,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $e3 = explode('.', $alias); - if(count($e3) > 1) { + if (count($e3) > 1) { $alias = $e3[1]; $owner = $e3[0]; } @@ -291,14 +316,12 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { list($dql, $alias) = $value; $sql = $this->createSubquery()->parseQuery($dql, false)->getQuery(); - - reset($this->tableAliases); - - $tableAlias = current($this->tableAliases); - reset($this->compAliases); - - $componentAlias = key($this->compAliases); + + + reset($this->_aliasMap); + $componentAlias = key($this->_aliasMap); + $tableAlias = $this->getTableAlias($componentAlias); $sqlAlias = $tableAlias . '__' . count($this->aggregateMap); @@ -313,14 +336,12 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { } public function processPendingAggregates($componentAlias) { - $tableAlias = $this->getTableAlias($componentAlias); + $tableAlias = $this->getTableAlias($componentAlias); + + $map = reset($this->_aliasMap); + $root = $map['table']; + $table = $this->_aliasMap[$componentAlias]['table']; - if ( ! isset($this->tables[$tableAlias])) { - throw new Doctrine_Query_Exception('Unknown component path ' . $componentAlias); - } - - $root = current($this->tables); - $table = $this->tables[$tableAlias]; $aggregates = array(); if(isset($this->pendingAggregates[$componentAlias])) { @@ -344,12 +365,12 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { if (is_numeric($arg)) { $arglist[] = $arg; } elseif (count($e) > 1) { - //$tableAlias = $this->getTableAlias($e[0]); - $table = $this->tables[$tableAlias]; + $map = $this->_aliasMap[$e[0]]; + $table = $map['table']; $e[1] = $table->getColumnName($e[1]); - if( ! $table->hasColumn($e[1])) { + if ( ! $table->hasColumn($e[1])) { throw new Doctrine_Query_Exception('Unknown column ' . $e[1]); } @@ -361,7 +382,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $sqlAlias = $tableAlias . '__' . count($this->aggregateMap); - if(substr($name, 0, 1) !== '(') { + if (substr($name, 0, 1) !== '(') { $this->parts['select'][] = $name . '(' . $distinct . implode(', ', $arglist) . ') AS ' . $sqlAlias; } else { $this->parts['select'][] = $name . ' AS ' . $sqlAlias; @@ -369,329 +390,6 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $this->aggregateMap[$alias] = $sqlAlias; $this->neededTables[] = $tableAlias; } - } - /** - * count - * - * @param array $params - * @return integer - */ - public function count($params = array()) - { - $parts_old = $this->parts; - - $this->remove('select'); - $join = $this->join; - $where = $this->where; - $having = $this->having; - $table = reset($this->tables); - - $q = 'SELECT COUNT(DISTINCT ' . $this->aliasHandler->getShortAlias($table->getTableName()) - . '.' . $table->getIdentifier() - . ') FROM ' . $table->getTableName() . ' ' . $this->aliasHandler->getShortAlias($table->getTableName()); - - foreach($join as $j) { - $q .= ' '.implode(' ',$j); - } - $string = $this->applyInheritance(); - - if( ! empty($where)) { - $q .= ' WHERE ' . implode(' AND ', $where); - if( ! empty($string)) - $q .= ' AND (' . $string . ')'; - } else { - if( ! empty($string)) - $q .= ' WHERE (' . $string . ')'; - } - - if( ! empty($having)) - $q .= ' HAVING ' . implode(' AND ',$having); - - if( ! is_array($params)) - $params = array($params); - - $params = array_merge($this->params, $params); - - $this->parts = $parts_old; - return (int) $this->getConnection()->fetchOne($q, $params); - } - /** - * loadFields - * loads fields for a given table and - * constructs a little bit of sql for every field - * - * fields of the tables become: [tablename].[fieldname] as [tablename]__[fieldname] - * - * @access private - * @param object Doctrine_Table $table a Doctrine_Table object - * @param integer $fetchmode fetchmode the table is using eg. Doctrine::FETCH_LAZY - * @param array $names fields to be loaded (only used in lazy property loading) - * @return void - */ - protected function loadFields(Doctrine_Table $table, $fetchmode, array $names, $cpath) - { - $name = $table->getComponentName(); - - switch($fetchmode): - case Doctrine::FETCH_OFFSET: - $this->limit = $table->getAttribute(Doctrine::ATTR_COLL_LIMIT); - case Doctrine::FETCH_IMMEDIATE: - if( ! empty($names)) { - // only auto-add the primary key fields if this query object is not - // a subquery of another query object - $names = array_unique(array_merge($table->getPrimaryKeys(), $names)); - } else { - $names = $table->getColumnNames(); - } - break; - case Doctrine::FETCH_LAZY_OFFSET: - $this->limit = $table->getAttribute(Doctrine::ATTR_COLL_LIMIT); - case Doctrine::FETCH_LAZY: - case Doctrine::FETCH_BATCH: - $names = array_unique(array_merge($table->getPrimaryKeys(), $names)); - break; - default: - throw new Doctrine_Exception("Unknown fetchmode."); - endswitch; - - $component = $table->getComponentName(); - $tablename = $this->tableAliases[$cpath]; - - $this->fetchModes[$tablename] = $fetchmode; - - $count = count($this->tables); - - foreach($names as $name) { - if($count == 0) { - $this->parts['select'][] = $tablename . '.' . $name; - } else { - $this->parts['select'][] = $tablename . '.' . $name . ' AS ' . $tablename . '__' . $name; - } - } - } - /** - * addFrom - * - * @param strint $from - * @return Doctrine_Query - */ - public function addFrom($from) - { - $class = 'Doctrine_Query_From'; - $parser = new $class($this); - $parser->parse($from); - - return $this; - } - /** - * leftJoin - * - * @param strint $join - * @return Doctrine_Query - */ - public function leftJoin($join) - { - $class = 'Doctrine_Query_From'; - $parser = new $class($this); - $parser->parse('LEFT JOIN ' . $join); - - return $this; - } - /** - * innerJoin - * - * @param strint $join - * @return Doctrine_Query - */ - public function innerJoin($join) - { - $class = 'Doctrine_Query_From'; - $parser = new $class($this); - $parser->parse('INNER JOIN ' . $join); - - return $this; - } - /** - * addOrderBy - * - * @param strint $orderby - * @return Doctrine_Query - */ - public function addOrderBy($orderby) - { - if (empty($orderby)) { - return $this; - } - $class = 'Doctrine_Query_Orderby'; - $parser = new $class($this); - $this->parts['orderby'][] = $parser->parse($orderby); - - return $this; - } - /** - * addWhere - * - * @param string $where - * @param mixed $params - */ - public function addWhere($where, $params = array()) - { - $class = 'Doctrine_Query_Where'; - $parser = new $class($this); - $this->parts['where'][] = $parser->parse($where); - - if(is_array($params)) { - $this->params = array_merge($this->params, $params); - } else { - $this->params[] = $params; - } - - return $this; - } - /** - * addSelect - * - * @param string $select - */ - public function addSelect($select) - { - $this->type = self::SELECT; - - $this->parseSelect($select); - - return $this; - } - /** - * addHaving - * - * @param string $having - */ - public function addHaving($having) - { - $class = 'Doctrine_Query_Having'; - $parser = new $class($this); - $this->parts['having'][] = $parser->parse($having); - - return $this; - } - /** - * sets a query part - * - * @param string $name - * @param array $args - * @return void - */ - public function __call($name, $args) - { - $name = strtolower($name); - - $method = 'parse' . ucwords($name); - - switch($name) { - case 'select': - $this->type = self::SELECT; - - if ( ! isset($args[0])) { - throw new Doctrine_Query_Exception('Empty select part'); - } - $this->parseSelect($args[0]); - break; - case 'delete': - $this->type = self::DELETE; - break; - case 'update': - $this->type = self::UPDATE; - $name = 'from'; - case 'from': - $this->parts['from'] = array(); - $this->parts['select'] = array(); - $this->parts['join'] = array(); - $this->joins = array(); - $this->tables = array(); - $this->fetchModes = array(); - $this->tableIndexes = array(); - $this->tableAliases = array(); - $this->aliasHandler->clear(); - - $class = "Doctrine_Query_".ucwords($name); - $parser = new $class($this); - - $parser->parse($args[0]); - break; - case 'where': - if(isset($args[1])) { - if(is_array($args[1])) { - $this->params = $args[1]; - } else { - $this->params = array($args[1]); - } - } - case 'having': - case 'orderby': - case 'groupby': - if (empty($args[0])) { - return $this; - } - - $class = 'Doctrine_Query_' . ucwords($name); - $parser = new $class($this); - - $this->parts[$name] = array($parser->parse($args[0])); - break; - case 'limit': - case 'offset': - if($args[0] == null) { - $args[0] = false; - } - - $this->parts[$name] = $args[0]; - break; - default: - $this->parts[$name] = array(); - if (method_exists($this, $method)) { - $this->$method($args[0]); - } - - throw new Doctrine_Query_Exception("Unknown overload method"); - } - - - return $this; - } - /** - * returns a query part - * - * @param $name query part name - * @return mixed - */ - public function get($name) - { - if( ! isset($this->parts[$name])) - return false; - - return $this->parts[$name]; - } - /** - * set - * sets a query SET part - * this method should only be used with UPDATE queries - * - * @param $name name of the field - * @param $value field value - * @return Doctrine_Query - */ - public function set($name, $value) - { - $class = new Doctrine_Query_Set($this); - $this->parts['set'][] = $class->parse($name . ' = ' . $value); - - return $this; - } - /** - * @return boolean - */ - public function isLimitSubqueryUsed() { - return $this->limitSubqueryUsed; } /** * getQueryBase @@ -704,15 +402,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { { switch ($this->type) { case self::DELETE: - /** - no longer needed? - - if ($this->conn->getName() == 'Mysql') { - $q = 'DELETE ' . end($this->tableAliases) . ' FROM '; - } else { - */ - $q = 'DELETE FROM '; - // } + $q = 'DELETE FROM '; break; case self::UPDATE: $q = 'UPDATE '; @@ -720,11 +410,57 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { case self::SELECT: $distinct = ($this->isDistinct()) ? 'DISTINCT ' : ''; - $q = 'SELECT '.$distinct.implode(', ', $this->parts['select']).' FROM '; + $q = 'SELECT ' . $distinct . implode(', ', $this->parts['select']) . ' FROM '; break; } return $q; } + /** + * buildFromPart + * + * @return string + */ + public function buildFromPart() + { + $q = ''; + foreach ($this->parts['from'] as $k => $part) { + if ($k === 0) { + $q .= $part; + continue; + } + // preserve LEFT JOINs only if needed + + if (substr($part, 0, 9) === 'LEFT JOIN') { + $e = explode(' ', $part); + + $aliases = array_merge($this->subqueryAliases, + array_keys($this->neededTables)); + + if( ! in_array($e[3], $aliases) && + ! in_array($e[2], $aliases) && + + ! empty($this->pendingFields)) { + continue; + } + + } + + $e = explode(' ON ', $part); + + // we can always be sure that the first join condition exists + $e2 = explode(' AND ', $e[1]); + + $part = $e[0] . ' ON ' . array_shift($e2); + + if ( ! empty($e2)) { + $parser = new Doctrine_Query_JoinCondition($this); + $part .= ' AND ' . $parser->_parse(implode(' AND ', $e2)); + } + + $q .= ' ' . $part; + } + return $q; + } /** * builds the sql query from the given parameters and applies things such as * column aggregation inheritance and limit subqueries if needed @@ -735,15 +471,17 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { */ public function getQuery($params = array()) { - if(empty($this->parts["select"]) || empty($this->parts["from"])) + if (empty($this->parts['select']) || empty($this->parts['from'])) { return false; + } $needsSubQuery = false; $subquery = ''; - $k = array_keys($this->tables); - $table = $this->tables[$k[0]]; + $map = reset($this->_aliasMap); + $table = $map['table']; + $rootAlias = key($this->_aliasMap); - if( ! empty($this->parts['limit']) && $this->needsSubquery && $table->getAttribute(Doctrine::ATTR_QUERY_LIMIT) == Doctrine::LIMIT_RECORDS) { + if ( ! empty($this->parts['limit']) && $this->needsSubquery && $table->getAttribute(Doctrine::ATTR_QUERY_LIMIT) == Doctrine::LIMIT_RECORDS) { $needsSubQuery = true; $this->limitSubqueryUsed = true; } @@ -754,118 +492,74 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { // build the basic query $str = ''; - if($this->isDistinct()) + if ($this->isDistinct()) { $str = 'DISTINCT '; - - $q = $this->getQueryBase(); - - $q .= $this->parts['from']; - /** - var_dump($this->pendingFields); - var_dump($this->subqueryAliases); */ - //var_dump($this->parts['join']); - - foreach($this->parts['join'] as $parts) { - foreach($parts as $part) { - // preserve LEFT JOINs only if needed - - if(substr($part, 0,9) === 'LEFT JOIN') { - $e = explode(' ', $part); - - $aliases = array_merge($this->subqueryAliases, - array_keys($this->neededTables)); - - - if( ! in_array($e[3], $aliases) && - ! in_array($e[2], $aliases) && - - ! empty($this->pendingFields)) { - continue; - } - - } - - $e = explode(' ON ', $part); - - // we can always be sure that the first join condition exists - $e2 = explode(' AND ', $e[1]); - - $part = $e[0] . ' ON ' - . array_shift($e2); - - if( ! empty($e2)) { - $parser = new Doctrine_Query_JoinCondition($this); - $part .= ' AND ' . $parser->parse(implode(' AND ', $e2)); - } - - $q .= ' ' . $part; - } } - /** - if( ! empty($this->parts['join'])) { - foreach($this->parts['join'] as $part) { - $q .= ' '.implode(' ', $part); - } - } - */ - if( ! empty($this->parts['set'])) { + $q = $this->getQueryBase(); + $q .= $this->buildFromPart(); + + if ( ! empty($this->parts['set'])) { $q .= ' SET ' . implode(', ', $this->parts['set']); } $string = $this->applyInheritance(); - if( ! empty($string)) - $this->parts['where'][] = '('.$string.')'; - + if ( ! empty($string)) { + $this->parts['where'][] = '(' . $string . ')'; + } $modifyLimit = true; - if( ! empty($this->parts["limit"]) || ! empty($this->parts["offset"])) { + if ( ! empty($this->parts["limit"]) || ! empty($this->parts["offset"])) { - if($needsSubQuery) { + if ($needsSubQuery) { $subquery = $this->getLimitSubquery(); - switch(strtolower($this->conn->getName())) { + switch (strtolower($this->conn->getName())) { case 'mysql': // mysql doesn't support LIMIT in subqueries $list = $this->conn->execute($subquery, $params)->fetchAll(PDO::FETCH_COLUMN); $subquery = implode(', ', $list); - break; + break; case 'pgsql': // pgsql needs special nested LIMIT subquery $subquery = 'SELECT doctrine_subquery_alias.' . $table->getIdentifier(). ' FROM (' . $subquery . ') AS doctrine_subquery_alias'; - break; + break; } - $field = $this->aliasHandler->getShortAlias($table->getTableName()) . '.' . $table->getIdentifier(); + $field = $this->aliasHandler->getShortAlias($rootAlias) . '.' . $table->getIdentifier(); // only append the subquery if it actually contains something - if($subquery !== '') + if ($subquery !== '') { array_unshift($this->parts['where'], $field. ' IN (' . $subquery . ')'); + } $modifyLimit = false; } } - $q .= ( ! empty($this->parts['where']))? ' WHERE ' . implode(' AND ', $this->parts['where']):''; - $q .= ( ! empty($this->parts['groupby']))? ' GROUP BY ' . implode(', ', $this->parts['groupby']):''; - $q .= ( ! empty($this->parts['having']))? ' HAVING ' . implode(' AND ', $this->parts['having']):''; - $q .= ( ! empty($this->parts['orderby']))? ' ORDER BY ' . implode(', ', $this->parts['orderby']):''; + $q .= ( ! empty($this->parts['where']))? ' WHERE ' . implode(' AND ', $this->parts['where']) : ''; + $q .= ( ! empty($this->parts['groupby']))? ' GROUP BY ' . implode(', ', $this->parts['groupby']) : ''; + $q .= ( ! empty($this->parts['having']))? ' HAVING ' . implode(' AND ', $this->parts['having']): ''; + $q .= ( ! empty($this->parts['orderby']))? ' ORDER BY ' . implode(', ', $this->parts['orderby']) : ''; - if($modifyLimit) + if ($modifyLimit) { $q = $this->conn->modifyLimitQuery($q, $this->parts['limit'], $this->parts['offset']); + } // return to the previous state - if( ! empty($string)) + if ( ! empty($string)) { array_pop($this->parts['where']); - if($needsSubQuery) + } + if ($needsSubQuery) { array_shift($this->parts['where']); - + } return $q; } /** + * getLimitSubquery * this is method is used by the record limit algorithm * * when fetching one-to-many, many-to-many associated data with LIMIT clause @@ -876,11 +570,12 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { */ public function getLimitSubquery() { - $k = array_keys($this->tables); - $table = $this->tables[$k[0]]; + $map = reset($this->_aliasMap); + $table = $map['table']; + $componentAlias = key($this->_aliasMap); // get short alias - $alias = $this->aliasHandler->getShortAlias($table->getTableName()); + $alias = $this->aliasHandler->getShortAlias($componentAlias); $primaryKey = $alias . '.' . $table->getIdentifier(); // initialize the base of the subquery @@ -899,23 +594,20 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { } } - $subquery .= ' FROM ' . $this->conn->quoteIdentifier($table->getTableName()) . ' ' . $alias; + $subquery .= ' FROM'; - foreach ($this->parts['join'] as $parts) { - foreach ($parts as $part) { - // preserve LEFT JOINs only if needed - if (substr($part,0,9) === 'LEFT JOIN') { - $e = explode(' ', $part); - - if ( ! in_array($e[3], $this->subqueryAliases) && - ! in_array($e[2], $this->subqueryAliases)) { - continue; - } + foreach ($this->parts['from'] as $part) { + // preserve LEFT JOINs only if needed + if (substr($part,0,9) === 'LEFT JOIN') { + $e = explode(' ', $part); + if ( ! in_array($e[3], $this->subqueryAliases) && + ! in_array($e[2], $this->subqueryAliases)) { + continue; } - - $subquery .= ' '.$part; } + + $subquery .= ' ' . $part; } // all conditions must be preserved in subquery @@ -927,7 +619,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { // add driver specific limit clause $subquery = $this->conn->modifyLimitQuery($subquery, $this->parts['limit'], $this->parts['offset']); - $parts = self::quoteExplode($subquery, ' ', "'", "'"); + $parts = Doctrine_Tokenizer::quoteExplode($subquery, ' ', "'", "'"); foreach($parts as $k => $part) { if(strpos($part, "'") !== false) { @@ -953,31 +645,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return $subquery; } /** - * query the database with DQL (Doctrine Query Language) - * - * @param string $query DQL query - * @param array $params parameters - */ - public function query($query,$params = array()) - { - $this->parseQuery($query); - - if($this->aggregate) { - $keys = array_keys($this->tables); - $query = $this->getQuery(); - $stmt = $this->tables[$keys[0]]->getConnection()->select($query, $this->parts["limit"], $this->parts["offset"]); - $data = $stmt->fetch(PDO::FETCH_ASSOC); - if(count($data) == 1) { - return current($data); - } else { - return $data; - } - } else { - return $this->execute($params); - } - } - /** - * splitQuery + * tokenizeQuery * splits the given dql query into an array where keys * represent different query part names and values are * arrays splitted using sqlExplode method @@ -995,9 +663,9 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @throws Doctrine_Query_Exception if some generic parsing error occurs * @return array an array containing the query string parts */ - public function splitQuery($query) + public function tokenizeQuery($query) { - $e = self::sqlExplode($query, ' '); + $e = Doctrine_Tokenizer::sqlExplode($query, ' '); foreach($e as $k=>$part) { $part = trim($part); @@ -1047,60 +715,61 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { */ public function parseQuery($query, $clear = true) { - if($clear) + if ($clear) { $this->clear(); + } $query = trim($query); $query = str_replace("\n", ' ', $query); $query = str_replace("\r", ' ', $query); - $parts = $this->splitQuery($query); + $parts = $this->tokenizeQuery($query); foreach($parts as $k => $part) { $part = implode(' ', $part); - switch(strtoupper($k)) { - case 'CREATE': + switch(strtolower($k)) { + case 'create': $this->type = self::CREATE; break; - case 'INSERT': + case 'insert': $this->type = self::INSERT; break; - case 'DELETE': + case 'delete': $this->type = self::DELETE; break; - case 'SELECT': + case 'select': $this->type = self::SELECT; $this->parseSelect($part); break; - case 'UPDATE': + case 'update': $this->type = self::UPDATE; $k = 'FROM'; - case 'FROM': + case 'from': $class = 'Doctrine_Query_' . ucwords(strtolower($k)); $parser = new $class($this); $parser->parse($part); break; - case 'SET': + case 'set': $class = 'Doctrine_Query_' . ucwords(strtolower($k)); $parser = new $class($this); - $this->parts['set'][] = $parser->parse($part); + $parser->parse($part); break; - case 'GROUP': - case 'ORDER': + case 'group': + case 'order': $k .= 'by'; - case 'WHERE': - case 'HAVING': + case 'where': + case 'having': $class = 'Doctrine_Query_' . ucwords(strtolower($k)); $parser = new $class($this); $name = strtolower($k); - $this->parts[$name][] = $parser->parse($part); + $parser->parse($part); break; - case 'LIMIT': + case 'limit': $this->parts['limit'] = trim($part); break; - case 'OFFSET': + case 'offset': $this->parts['offset'] = trim($part); break; } @@ -1108,573 +777,518 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { return $this; } - /** - * DQL ORDER BY PARSER - * parses the order by part of the query string - * - * @param string $str - * @return void - */ - final public function parseOrderBy($str) + public function load($path, $loadFields = true) { - $parser = new Doctrine_Query_Part_Orderby($this); - return $parser->parse($str); - } - /** - * returns Doctrine::FETCH_* constant - * - * @param string $mode - * @return integer - */ - final public function parseFetchMode($mode) - { - switch(strtolower($mode)): - case "i": - case "immediate": - $fetchmode = Doctrine::FETCH_IMMEDIATE; - break; - case "b": - case "batch": - $fetchmode = Doctrine::FETCH_BATCH; - break; - case "l": - case "lazy": - $fetchmode = Doctrine::FETCH_LAZY; - break; - case "o": - case "offset": - $fetchmode = Doctrine::FETCH_OFFSET; - break; - case "lo": - case "lazyoffset": - $fetchmode = Doctrine::FETCH_LAZYOFFSET; - default: - throw new Doctrine_Query_Exception("Unknown fetchmode '$mode'. The availible fetchmodes are 'i', 'b' and 'l'."); - endswitch; - return $fetchmode; - } - /** - * trims brackets - * - * @param string $str - * @param string $e1 the first bracket, usually '(' - * @param string $e2 the second bracket, usually ')' - */ - public static function bracketTrim($str,$e1 = '(',$e2 = ')') - { - if(substr($str,0,1) == $e1 && substr($str,-1) == $e2) - return substr($str,1,-1); - else - return $str; - } - /** - * bracketExplode - * - * example: - * - * parameters: - * $str = (age < 20 AND age > 18) AND email LIKE 'John@example.com' - * $d = ' AND ' - * $e1 = '(' - * $e2 = ')' - * - * would return an array: - * array("(age < 20 AND age > 18)", - * "email LIKE 'John@example.com'") - * - * @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 ')' - * - */ - public static function bracketExplode($str, $d = ' ', $e1 = '(', $e2 = ')') - { - if(is_array($d)) { - $a = preg_split('/('.implode('|', $d).')/', $str); - $d = stripslashes($d[0]); - } else - $a = explode("$d",$str); - - $i = 0; - $term = array(); - foreach($a as $key=>$val) { - if (empty($term[$i])) { - $term[$i] = trim($val); - $s1 = substr_count($term[$i], "$e1"); - $s2 = substr_count($term[$i], "$e2"); - if($s1 == $s2) $i++; - } else { - $term[$i] .= "$d".trim($val); - $c1 = substr_count($term[$i], "$e1"); - $c2 = substr_count($term[$i], "$e2"); - if($c1 == $c2) $i++; - } - } - return $term; - } - /** - * quoteExplode - * - * example: - * - * parameters: - * $str = email LIKE 'John@example.com' - * $d = ' AND ' - * - * would return an array: - * array("email", "LIKE", "'John@example.com'") - * - * @param string $str - * @param string $d the delimeter which explodes the string - */ - public static function quoteExplode($str, $d = ' ') - { - if(is_array($d)) { - $a = preg_split('/('.implode('|', $d).')/', $str); - $d = stripslashes($d[0]); - } else - $a = explode("$d",$str); - - $i = 0; - $term = array(); - foreach($a as $key => $val) { - if (empty($term[$i])) { - $term[$i] = trim($val); - - if( ! (substr_count($term[$i], "'") & 1)) - $i++; - } else { - $term[$i] .= "$d".trim($val); - - if( ! (substr_count($term[$i], "'") & 1)) - $i++; - } - } - return $term; - } - /** - * sqlExplode - * - * explodes a string into array using custom brackets and - * quote delimeters - * - * - * example: - * - * parameters: - * $str = "(age < 20 AND age > 18) AND name LIKE 'John Doe'" - * $d = ' ' - * $e1 = '(' - * $e2 = ')' - * - * would return an array: - * array('(age < 20 AND age > 18)', - * 'name', - * 'LIKE', - * 'John Doe') - * - * @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 = ')') - { - if ($d == ' ') { - $d = array(' ', '\s'); - } - if(is_array($d)) { - if (in_array(' ', $d)) { - $d[] = '\s'; - } - $str = preg_split('/('.implode('|', $d).')/', $str); - $d = stripslashes($d[0]); - } else { - $str = explode("$d",$str); - } - - $i = 0; - $term = array(); - foreach($str as $key => $val) { - if (empty($term[$i])) { - $term[$i] = trim($val); - - $s1 = substr_count($term[$i],"$e1"); - $s2 = substr_count($term[$i],"$e2"); - - if (substr($term[$i],0,1) == "(") { - if($s1 == $s2) { - $i++; - } - } else { - if ( ! (substr_count($term[$i], "'") & 1) && - ! (substr_count($term[$i], "\"") & 1) && - ! (substr_count($term[$i], "�") & 1) - ) { $i++; } - } - } else { - $term[$i] .= "$d".trim($val); - $c1 = substr_count($term[$i],"$e1"); - $c2 = substr_count($term[$i],"$e2"); - - if(substr($term[$i],0,1) == "(") { - if($c1 == $c2) { - $i++; - } - } else { - if ( ! (substr_count($term[$i], "'") & 1) && - ! (substr_count($term[$i], "\"") & 1) && - ! (substr_count($term[$i], "�") & 1) - ) { $i++; } - } - } - } - return $term; - } - /** - * generateAlias - * - * @param string $tableName - * @return string - */ - public function generateAlias($tableName) - { - if(isset($this->tableIndexes[$tableName])) { - return $tableName.++$this->tableIndexes[$tableName]; - } else { - $this->tableIndexes[$tableName] = 1; - return $tableName; - } - } - - /** - * loads a component - * - * @param string $path the path of the loadable component - * @param integer $fetchmode optional fetchmode, if not set the components default fetchmode will be used - * @throws Doctrine_Query_Exception - * @return Doctrine_Table - */ - final public function load($path, $loadFields = true) - { - // parse custom join conditions $e = explode(' ON ', $path); $joinCondition = ''; - if(count($e) > 1) { + + if (count($e) > 1) { $joinCondition = ' AND ' . $e[1]; $path = $e[0]; } - $tmp = explode(' ',$path); - $componentAlias = (count($tmp) > 1) ? end($tmp) : false; + $tmp = explode(' ', $path); + $originalAlias = (count($tmp) > 1) ? end($tmp) : null; $e = preg_split("/[.:]/", $tmp[0], -1); + $fullPath = $tmp[0]; + $prevPath = ''; + $fullLength = strlen($fullPath); - if(isset($this->compAliases[$e[0]])) { - $end = substr($tmp[0], strlen($e[0])); - $path = $this->compAliases[$e[0]] . $end; - $e = preg_split("/[.:]/", $path, -1); - } else { - $path = $tmp[0]; + if (isset($this->_aliasMap[$e[0]])) { + $table = $this->_aliasMap[$e[0]]['table']; + + $prevPath = $parent = array_shift($e); } + foreach ($e as $key => $name) { + // get length of the previous path + $length = strlen($prevPath); + // build the current component path + $prevPath = ($prevPath) ? $prevPath . '.' . $name : $name; - $index = 0; - $currPath = ''; - $this->tableStack = array(); + $delimeter = substr($fullPath, $length, 1); - foreach($e as $key => $fullname) { - try { - $e2 = preg_split("/[-(]/",$fullname); - $name = $e2[0]; + // if an alias is not given use the current path as an alias identifier + if (strlen($prevPath) === $fullLength && isset($originalAlias)) { + $componentAlias = $originalAlias; + } else { + $componentAlias = $prevPath; + } - $currPath .= '.' . $name; + if ( ! isset($table)) { + // process the root of the path - if($key == 0) { - $currPath = substr($currPath,1); + $table = $this->loadRoot($name, $componentAlias); + } else { + $join = ($delimeter == ':') ? 'INNER JOIN ' : 'LEFT JOIN '; - $this->conn = Doctrine_Manager::getInstance() - ->getConnectionForComponent($name); + $relation = $table->getRelation($name); - $table = $this->conn->getTable($name); + $this->_aliasMap[$componentAlias] = array('table' => $relation->getTable(), + 'parent' => $parent, + 'relation' => $relation); + if ( ! $relation->isOneToOne()) { + $this->needsSubquery = true; + } + $localAlias = $this->getShortAlias($parent, $table->getTableName()); + $foreignAlias = $this->getShortAlias($componentAlias, $relation->getTable()->getTableName()); + $localSql = $this->conn->quoteIdentifier($table->getTableName()) . ' ' . $localAlias; + $foreignSql = $this->conn->quoteIdentifier($relation->getTable()->getTableName()) . ' ' . $foreignAlias; - $tname = $this->aliasHandler->getShortAlias($table->getTableName()); + $map = $relation->getTable()->inheritanceMap; + + if ( ! $loadFields || ! empty($map) || $joinCondition) { + $this->subqueryAliases[] = $foreignAlias; + } - if( ! isset($this->tableAliases[$currPath])) { - $this->tableIndexes[$tname] = 1; - } - - $this->parts['from'] = $this->conn->quoteIdentifier($table->getTableName()); - - if ($this->type === self::SELECT) { - $this->parts['from'] .= ' ' . $tname; + if ($relation instanceof Doctrine_Relation_Association) { + $asf = $relation->getAssociationFactory(); + + $assocTableName = $asf->getTableName(); + + if( ! $loadFields || ! empty($map) || $joinCondition) { + $this->subqueryAliases[] = $assocTableName; } - $this->tableAliases[$currPath] = $tname; + $assocPath = $prevPath . '.' . $asf->getComponentName(); + + $assocAlias = $this->getShortAlias($assocPath, $asf->getTableName()); + + $queryPart = $join . $assocTableName . ' ' . $assocAlias . ' ON ' . $localAlias . '.' + . $table->getIdentifier() . ' = ' + . $assocAlias . '.' . $relation->getLocal(); + + if ($relation instanceof Doctrine_Relation_Association_Self) { + $queryPart .= ' OR ' . $localAlias . '.' . $table->getIdentifier() . ' = ' + . $assocAlias . '.' . $relation->getForeign(); + } + + $this->parts['from'][] = $queryPart; + + $queryPart = $join . $foreignSql . ' ON ' . $foreignAlias . '.' + . $relation->getTable()->getIdentifier() . ' = ' + . $assocAlias . '.' . $relation->getForeign() + . $joinCondition; + + if ($relation instanceof Doctrine_Relation_Association_Self) { + $queryPart .= ' OR ' . $foreignAlias . '.' . $table->getIdentifier() . ' = ' + . $assocAlias . '.' . $relation->getLocal(); + } - $tableName = $tname; } else { - $index += strlen($e[($key - 1)]) + 1; - // the mark here is either '.' or ':' - $mark = substr($path, ($index - 1), 1); - - if(isset($this->tableAliases[$prevPath])) { - $tname = $this->tableAliases[$prevPath]; - } else { - $tname = $this->aliasHandler->getShortAlias($table->getTableName()); - } - - $fk = $table->getRelation($name); - $name = $fk->getTable()->getComponentName(); - $original = $fk->getTable()->getTableName(); - - - - if (isset($this->tableAliases[$currPath])) { - $tname2 = $this->tableAliases[$currPath]; - } else { - $tname2 = $this->aliasHandler->generateShortAlias($original); - } - - $aliasString = $this->conn->quoteIdentifier($original) . ' ' . $tname2; - - switch ($mark) { - case ':': - $join = 'INNER JOIN '; - break; - case '.': - $join = 'LEFT JOIN '; - break; - default: - throw new Doctrine_Query_Exception("Unknown operator '$mark'"); - } - - if( ! $fk->isOneToOne()) { - $this->needsSubquery = true; - } - - - $map = $fk->getTable()->inheritanceMap; - - if( ! $loadFields || ! empty($map) || $joinCondition) { - $this->subqueryAliases[] = $tname2; - } - - - if ($fk instanceof Doctrine_Relation_Association) { - $asf = $fk->getAssociationFactory(); - - $assocTableName = $asf->getTableName(); - - if( ! $loadFields || ! empty($map) || $joinCondition) { - $this->subqueryAliases[] = $assocTableName; - } - - $assocPath = $prevPath . '.' . $asf->getComponentName(); - - if (isset($this->tableAliases[$assocPath])) { - $assocAlias = $this->tableAliases[$assocPath]; - } else { - $assocAlias = $this->aliasHandler->generateShortAlias($assocTableName); - } - - $this->parts['join'][$tname][$assocTableName] = $join . $assocTableName . ' ' . $assocAlias . ' ON ' . $tname . '.' - . $table->getIdentifier() . ' = ' - . $assocAlias . '.' . $fk->getLocal(); - - if ($fk instanceof Doctrine_Relation_Association_Self) { - $this->parts['join'][$tname][$assocTableName] .= ' OR ' . $tname . '.' . $table->getIdentifier() . ' = ' - . $assocAlias . '.' . $fk->getForeign(); - } - - $this->parts['join'][$tname][$tname2] = $join . $aliasString . ' ON ' . $tname2 . '.' - . $fk->getTable()->getIdentifier() . ' = ' - . $assocAlias . '.' . $fk->getForeign() - . $joinCondition; - - if ($fk instanceof Doctrine_Relation_Association_Self) { - $this->parts['join'][$tname][$tname2] .= ' OR ' . $tname2 . '.' . $table->getIdentifier() . ' = ' - . $assocAlias . '.' . $fk->getLocal(); - } - - } else { - $this->parts['join'][$tname][$tname2] = $join . $aliasString - . ' ON ' . $tname . '.' - . $fk->getLocal() . ' = ' . $tname2 . '.' . $fk->getForeign() - . $joinCondition; - } - - - $this->joins[$tname2] = $prevTable; - - - $table = $fk->getTable(); - - $this->tableAliases[$currPath] = $tname2; - - $tableName = $tname2; - - $this->relationStack[] = $fk; + $queryPart = $join . $foreignSql + . ' ON ' . $localAlias . '.' + . $relation->getLocal() . ' = ' . $foreignAlias . '.' . $relation->getForeign() + . $joinCondition; } - - $this->components[$currPath] = $table; - - $this->tableStack[] = $table; - - if( ! isset($this->tables[$tableName])) { - $this->tables[$tableName] = $table; - - if ($loadFields) { - - $skip = false; - - if ( ! empty($this->pendingFields) || - ! empty($this->pendingAggregates)) { - $skip = true; - } - - if ($componentAlias) { - $this->compAliases[$componentAlias] = $currPath; - - if(isset($this->pendingFields[$componentAlias])) { - $this->processPendingFields($componentAlias); - $skip = true; - } - if(isset($this->pendingAggregates[$componentAlias]) || - (current($this->tables) === $table && isset($this->pendingAggregates[0])) - ) { - $this->processPendingAggregates($componentAlias); - $skip = true; - } - } - - if ( ! $skip) { - $this->parseFields($fullname, $tableName, $e2, $currPath); - } - } - } - - - $prevPath = $currPath; - $prevTable = $tableName; - } catch(Exception $e) { - throw new Doctrine_Query_Exception($e->__toString()); + $this->parts['from'][] = $queryPart; } + if ($loadFields) { + + $restoreState = false; + // load fields if necessary + if ($loadFields && empty($this->pendingFields) + && empty($this->pendingAggregates) + && empty($this->pendingSubqueries)) { + + $this->pendingFields[$componentAlias] = array('*'); + + $restoreState = true; + } + + if(isset($this->pendingFields[$componentAlias])) { + $this->processPendingFields($componentAlias); + } + + if(isset($this->pendingAggregates[$componentAlias]) || isset($this->pendingAggregates[0])) { + $this->processPendingAggregates($componentAlias); + } + + if ($restoreState) { + $this->pendingFields = array(); + $this->pendingAggregates = array(); + } + } + $parent = $prevPath; + } + return end($this->_aliasMap); + } + /** + * loadRoot + * + * @param string $name + * @param string $componentAlias + */ + public function loadRoot($name, $componentAlias) + { + // get the connection for the component + $this->conn = Doctrine_Manager::getInstance() + ->getConnectionForComponent($name); + + $table = $this->conn->getTable($name); + $tableName = $table->getTableName(); + + // get the short alias for this table + $tableAlias = $this->aliasHandler->getShortAlias($componentAlias, $tableName); + // quote table name + $queryPart = $this->conn->quoteIdentifier($tableName); + + if ($this->type === self::SELECT) { + $queryPart .= ' ' . $tableAlias; } - if($componentAlias !== false) { - $this->compAliases[$componentAlias] = $currPath; - } - + $this->parts['from'][] = $queryPart; + $this->tableAliases[$tableAlias] = $componentAlias; + $this->_aliasMap[$componentAlias] = array('table' => $table); + return $table; } - /** - * parseFields + /** + * count + * fetches the count of the query + * + * This method executes the main query without all the + * selected fields, ORDER BY part, LIMIT part and OFFSET part. * - * @param string $fullName - * @param string $tableName - * @param array $exploded - * @param string $currPath - * @return void + * Example: + * Main query: + * SELECT u.*, p.phonenumber FROM User u + * LEFT JOIN u.Phonenumber p + * WHERE p.phonenumber = '123 123' LIMIT 10 + * + * The query this method executes: + * SELECT COUNT(DISTINCT u.id) FROM User u + * LEFT JOIN u.Phonenumber p + * WHERE p.phonenumber = '123 123' + * + * @param array $params an array of prepared statement parameters + * @return integer the count of this query */ - final public function parseFields($fullName, $tableName, array $exploded, $currPath) + public function count($params = array()) { - $table = $this->tables[$tableName]; + // initialize temporary variables + $where = $this->parts['where']; + $having = $this->parts['having']; + $map = reset($this->_aliasMap); + $componentAlias = key($this->_aliasMap); + $table = $map['table']; - $fields = array(); + // build the query base + $q = 'SELECT COUNT(DISTINCT ' . $this->aliasHandler->getShortAlias($table->getTableName()) + . '.' . $table->getIdentifier() + . ') FROM ' . $this->buildFromPart(); - 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)); - } - } - } 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) { - - } else { - $fields = explode(',', substr($exploded[2],0,-1)); - } - } + // append column aggregation inheritance (if needed) + $string = $this->applyInheritance(); + if ( ! empty($string)) { + $where[] = $string; } - if( ! $this->aggregate) - $this->loadFields($table, $fetchmode, $fields, $currPath); + // append conditions + $q .= ( ! empty($where)) ? ' WHERE ' . implode(' AND ', $where) : ''; + $q .= ( ! empty($having)) ? ' HAVING ' . implode(' AND ', $having): ''; + + if ( ! is_array($params)) { + $params = array($params); + } + // append parameters + $params = array_merge($this->params, $params); + + return (int) $this->getConnection()->fetchOne($q, $params); + } + /** + * isLimitSubqueryUsed + * whether or not limit subquery algorithm is used + * + * @return boolean + */ + public function isLimitSubqueryUsed() { + return $this->limitSubqueryUsed; + } + + /** + * query + * query the database with DQL (Doctrine Query Language) + * + * @param string $query DQL query + * @param array $params prepared statement parameters + * @see Doctrine::FETCH_* constants + * @return mixed + */ + public function query($query, $params = array()) + { + $this->parseQuery($query); + + return $this->execute($params); } /** - * parseAggregateFunction + * getShortAlias + * some database such as Oracle need the identifier lengths to be < ~30 chars + * hence Doctrine creates as short identifier aliases as possible * - * @param string $func - * @param string $reference - * @return string + * this method is used for the creation of short table aliases, its also + * smart enough to check if an alias already exists for given component (componentAlias) + * + * @param string $componentAlias the alias for the query component to search table alias for + * @param string $tableName the table name from which the table alias is being created + * @return string the generated / fetched short alias */ - public function parseAggregateFunction($func,$reference) + public function getShortAlias($componentAlias, $tableName) { - $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; - } - } + return $this->aliasHandler->getShortAlias($componentAlias, $tableName); } /** - * parseAggregateValues + * addSelect + * adds fields to the SELECT part of the query + * + * @param string $select DQL SELECT part + * @return Doctrine_Query */ - public function parseAggregateValues($fullName, $tableName, array $exploded, $currPath) + public function addSelect($select) { - $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) { - $func = $this->parseAggregateFunction($value, $currPath); - $exploded[$k] = $func; - - $this->parts['select'][] = $exploded[$k]; + return $this->getParser('select')->parse($select, true); + } + /** + * addWhere + * adds conditions to the WHERE part of the query + * + * @param string $where DQL WHERE part + * @param mixed $params an array of parameters or a simple scalar + * @return Doctrine_Query + */ + public function addWhere($where, $params = array()) + { + if (is_array($params)) { + $this->params = array_merge($this->params, $params); + } else { + $this->params[] = $params; } + return $this->getParser('where')->parse($where, true); + } + /** + * addGroupBy + * adds fields to the GROUP BY part of the query + * + * @param string $groupby DQL GROUP BY part + * @return Doctrine_Query + */ + public function addGroupBy($groupby) + { + return $this->getParser('groupby')->parse($groupby, true); + } + /** + * addHaving + * adds conditions to the HAVING part of the query + * + * @param string $having DQL HAVING part + * @param mixed $params an array of parameters or a simple scalar + * @return Doctrine_Query + */ + public function addHaving($having, $params = array()) + { + if (is_array($params)) { + $this->params = array_merge($this->params, $params); + } else { + $this->params[] = $params; + } + return $this->getParser('having')->parse($having, true); + } + /** + * addOrderBy + * adds fields to the ORDER BY part of the query + * + * @param string $orderby DQL ORDER BY part + * @return Doctrine_Query + */ + public function addOrderBy($orderby) + { + return $this->getParser('orderby')->parse($orderby, true); + } + /** + * select + * sets the SELECT part of the query + * + * @param string $select DQL SELECT part + * @return Doctrine_Query + */ + public function select($select) + { + return $this->getParser('select')->parse($select); + } + /** + * distinct + * Makes the query SELECT DISTINCT. + * + * @param bool $flag Whether or not the SELECT is DISTINCT (default true). + * @return Doctrine_Query + */ + public function distinct($flag = true) + { + $this->_parts['distinct'] = (bool) $flag; + + return $this; + } + + /** + * forUpdate + * Makes the query SELECT FOR UPDATE. + * + * @param bool $flag Whether or not the SELECT is FOR UPDATE (default true). + * @return Doctrine_Query + */ + public function forUpdate($flag = true) + { + $this->_parts[self::FOR_UPDATE] = (bool) $flag; + + return $this; + } + /** + * delete + * sets the query type to DELETE + * + * @return Doctrine_Query + */ + public function delete() + { + $this->type = self::DELETE; + + return $this; + } + /** + * update + * sets the UPDATE part of the query + * + * @param string $update DQL UPDATE part + * @return Doctrine_Query + */ + public function update($update) + { + $this->type = self::UPDATE; + + return $this->getParser('from')->parse($update); + } + /** + * set + * sets the SET part of the query + * + * @param string $update DQL UPDATE part + * @return Doctrine_Query + */ + public function set($key, $value) + { + return $this->getParser('set')->parse($key . ' = ' . $value); + } + /** + * from + * sets the FROM part of the query + * + * @param string $from DQL FROM part + * @return Doctrine_Query + */ + public function from($from) + { + return $this->getParser('from')->parse($from); + } + /** + * innerJoin + * appends an INNER JOIN to the FROM part of the query + * + * @param string $join DQL INNER JOIN + * @return Doctrine_Query + */ + public function innerJoin($join) + { + return $this->getParser('from')->parse('INNER JOIN ' . $join); + } + /** + * leftJoin + * appends a LEFT JOIN to the FROM part of the query + * + * @param string $join DQL LEFT JOIN + * @return Doctrine_Query + */ + public function leftJoin($join) + { + return $this->getParser('from')->parse('LEFT JOIN ' . $join); + } + /** + * groupBy + * sets the GROUP BY part of the query + * + * @param string $groupby DQL GROUP BY part + * @return Doctrine_Query + */ + public function groupBy($groupby) + { + return $this->getParser('groupby')->parse($groupby); + } + /** + * where + * sets the WHERE part of the query + * + * @param string $join DQL WHERE part + * @param mixed $params an array of parameters or a simple scalar + * @return Doctrine_Query + */ + public function where($where, $params = array()) + { + $this->params = (array) $params; + + return $this->getParser('where')->parse($where); + } + /** + * having + * sets the HAVING part of the query + * + * @param string $having DQL HAVING part + * @param mixed $params an array of parameters or a simple scalar + * @return Doctrine_Query + */ + public function having($having, $params) + { + $this->params = (array) $params; + + return $this->getParser('having')->parse($having); + } + /** + * orderBy + * sets the ORDER BY part of the query + * + * @param string $orderby DQL ORDER BY part + * @return Doctrine_Query + */ + public function orderBy($orderby) + { + return $this->getParser('orderby')->parse($orderby); + } + /** + * limit + * sets the DQL query limit + * + * @param integer $limit limit to be used for limiting the query results + * @return Doctrine_Query + */ + public function limit($limit) + { + return $this->getParser('limit')->parse($limit); + } + /** + * offset + * sets the DQL query offset + * + * @param integer $offset offset to be used for paginating the query + * @return Doctrine_Query + */ + public function offset($offset) + { + return $this->getParser('offset')->parse($offset); } } diff --git a/lib/Doctrine/Query/Condition.php b/lib/Doctrine/Query/Condition.php index a6c531233..3ba0c0870 100644 --- a/lib/Doctrine/Query/Condition.php +++ b/lib/Doctrine/Query/Condition.php @@ -39,32 +39,32 @@ abstract class Doctrine_Query_Condition extends Doctrine_Query_Part * @param string $str * @return string */ - final public function parse($str) + public function _parse($str) { $tmp = trim($str); - $parts = Doctrine_Query::bracketExplode($str, array(' \&\& ', ' AND '), '(', ')'); + $parts = Doctrine_Tokenizer::bracketExplode($str, array(' \&\& ', ' AND '), '(', ')'); if (count($parts) > 1) { $ret = array(); foreach ($parts as $part) { - $part = Doctrine_Query::bracketTrim($part, '(', ')'); - $ret[] = $this->parse($part); + $part = Doctrine_Tokenizer::bracketTrim($part, '(', ')'); + $ret[] = $this->_parse($part); } - $r = implode(' AND ',$ret); + $r = implode(' AND ', $ret); } else { - $parts = Doctrine_Query::bracketExplode($str, array(' \|\| ', ' OR '), '(', ')'); + $parts = Doctrine_Tokenizer::bracketExplode($str, array(' \|\| ', ' OR '), '(', ')'); if (count($parts) > 1) { $ret = array(); foreach ($parts as $part) { - $part = Doctrine_Query::bracketTrim($part, '(', ')'); - $ret[] = $this->parse($part); + $part = Doctrine_Tokenizer::bracketTrim($part, '(', ')'); + $ret[] = $this->_parse($part); } $r = implode(' OR ', $ret); } else { - if (substr($parts[0],0,1) == '(' && substr($parts[0],-1) == ')') { - return $this->parse(substr($parts[0],1,-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]); } @@ -73,6 +73,9 @@ abstract class Doctrine_Query_Condition extends Doctrine_Query_Part return '(' . $r . ')'; } + + + /** * parses a literal value and returns the parsed value * @@ -88,7 +91,7 @@ abstract class Doctrine_Query_Condition extends Doctrine_Query_Part if (strpos($value, '\'') === false) { // parse booleans $value = $this->query->getConnection() - ->dataDict->parseBoolean($value); + ->dataDict->parseBoolean($value); $a = explode('.', $value); diff --git a/lib/Doctrine/Query/From.php b/lib/Doctrine/Query/From.php index b7ee4a2c7..41dcd0b37 100644 --- a/lib/Doctrine/Query/From.php +++ b/lib/Doctrine/Query/From.php @@ -31,7 +31,7 @@ Doctrine::autoload("Doctrine_Query_Part"); * @author Konsta Vesterinen */ class Doctrine_Query_From extends Doctrine_Query_Part -{ +{ /** * DQL FROM PARSER * parses the from part of the query string @@ -39,11 +39,10 @@ class Doctrine_Query_From extends Doctrine_Query_Part * @param string $str * @return void */ - final public function parse($str) + public function parse($str) { - $str = trim($str); - $parts = Doctrine_Query::bracketExplode($str, 'JOIN'); + $parts = Doctrine_Tokenizer::bracketExplode($str, 'JOIN'); $operator = false; @@ -52,8 +51,10 @@ class Doctrine_Query_From extends Doctrine_Query_Part $operator = ':'; case 'LEFT': array_shift($parts); + break; } + $last = ''; foreach ($parts as $k => $part) { @@ -70,7 +71,7 @@ class Doctrine_Query_From extends Doctrine_Query_Part } $part = implode(' ', $e); - foreach (Doctrine_Query::bracketExplode($part, ',') as $reference) { + foreach (Doctrine_Tokenizer::bracketExplode($part, ',') as $reference) { $reference = trim($reference); $e = explode('.', $reference); @@ -83,6 +84,7 @@ class Doctrine_Query_From extends Doctrine_Query_Part $operator = ($last == 'INNER') ? ':' : '.'; } + return $this->query; } } diff --git a/lib/Doctrine/Query/Groupby.php b/lib/Doctrine/Query/Groupby.php index 5d130e19c..3fe7c5d1c 100644 --- a/lib/Doctrine/Query/Groupby.php +++ b/lib/Doctrine/Query/Groupby.php @@ -39,7 +39,7 @@ class Doctrine_Query_Groupby extends Doctrine_Query_Part * @param string $str * @return void */ - final public function parse($str) + public function parse($str, $append = false) { $r = array(); foreach (explode(',', $str) as $reference) { @@ -47,10 +47,15 @@ class Doctrine_Query_Groupby extends Doctrine_Query_Part $e = explode('.', $reference); $field = array_pop($e); $ref = implode('.', $e); - $table = $this->query->load($ref); - $component = $table->getComponentName(); - $r[] = $this->query->getTableAlias($ref).".".$field; + $this->query->load($ref); + + $r[] = $this->query->getTableAlias($ref) . '.' . $field; } - return implode(', ', $r); + if ($append) { + $this->query->addQueryPart('groupby', implode(', ', $r)); + } else { + $this->query->setQueryPart('groupby', implode(', ', $r)); + } + return $this->query; } } diff --git a/lib/Doctrine/Query/Having.php b/lib/Doctrine/Query/Having.php index d491d6d31..e9fe27571 100644 --- a/lib/Doctrine/Query/Having.php +++ b/lib/Doctrine/Query/Having.php @@ -32,6 +32,15 @@ Doctrine::autoload('Doctrine_Query_Condition'); */ class Doctrine_Query_Having extends Doctrine_Query_Condition { + public function parse($str, $append = false) + { + if ($append) { + $this->query->addQueryPart('having', $this->_parse($str)); + } else { + $this->query->setQueryPart('having', $this->_parse($str)); + } + return $this->query; + } /** * DQL Aggregate Function parser * @@ -47,7 +56,7 @@ class Doctrine_Query_Having extends Doctrine_Query_Condition $name = substr($func, 0, $pos); $func = substr($func, ($pos + 1), -1); - $params = Doctrine_Query::bracketExplode($func, ',', '(', ')'); + $params = Doctrine_Tokenizer::bracketExplode($func, ',', '(', ')'); foreach ($params as $k => $param) { $params[$k] = $this->parseAggregateFunction($param); @@ -64,8 +73,8 @@ class Doctrine_Query_Having extends Doctrine_Query_Condition if (count($a) > 1) { $field = array_pop($a); $reference = implode('.', $a); - $table = $this->query->load($reference, false); - $field = $table->getColumnName($field); + $map = $this->query->load($reference, false); + $field = $map['table']->getColumnName($field); $func = $this->query->getTableAlias($reference) . '.' . $field; } else { $field = end($a); @@ -86,7 +95,7 @@ class Doctrine_Query_Having extends Doctrine_Query_Condition */ final public function load($having) { - $e = Doctrine_Query::bracketExplode($having, ' ', '(', ')'); + $e = Doctrine_Tokenizer::bracketExplode($having, ' ', '(', ')'); $r = array_shift($e); $t = explode('(', $r); diff --git a/lib/Doctrine/Query/JoinCondition.php b/lib/Doctrine/Query/JoinCondition.php index d4630c43a..f498a50e6 100644 --- a/lib/Doctrine/Query/JoinCondition.php +++ b/lib/Doctrine/Query/JoinCondition.php @@ -36,7 +36,7 @@ class Doctrine_Query_JoinCondition extends Doctrine_Query_Condition { $condition = trim($condition); - $e = Doctrine_Query::sqlExplode($condition); + $e = Doctrine_Tokenizer::sqlExplode($condition); if(count($e) > 2) { $a = explode('.', $e[0]); @@ -46,15 +46,15 @@ class Doctrine_Query_JoinCondition extends Doctrine_Query_Condition $value = $e[2]; $alias = $this->query->getTableAlias($reference); - - $table = $this->query->getTable($alias); + $map = $this->query->getDeclaration($reference); + $table = $map['table']; // check if value is enumerated value $enumIndex = $table->enumIndex($field, trim($value, "'")); if (substr($value, 0, 1) == '(') { // trim brackets - $trimmed = Doctrine_Query::bracketTrim($value); + $trimmed = Doctrine_Tokenizer::bracketTrim($value); if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') { // subquery found @@ -64,7 +64,7 @@ class Doctrine_Query_JoinCondition extends Doctrine_Query_Condition $value = '(' . substr($trimmed, 4) . ')'; } else { // simple in expression found - $e = Doctrine_Query::sqlExplode($trimmed, ','); + $e = Doctrine_Tokenizer::sqlExplode($trimmed, ','); $value = array(); foreach ($e as $part) { diff --git a/lib/Doctrine/Query/Limit.php b/lib/Doctrine/Query/Limit.php new file mode 100644 index 000000000..369084699 --- /dev/null +++ b/lib/Doctrine/Query/Limit.php @@ -0,0 +1,41 @@ +. + */ + +/** + * Doctrine_Query_Limit + * + * @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: 1352 $ + * @author Konsta Vesterinen + */ +class Doctrine_Query_Limit extends Doctrine_Query_Part +{ + public function parse($limit) + { + $this->query->setQueryPart('limit', (int) $limit); + + return $this->query; + } +} diff --git a/lib/Doctrine/Query/Offset.php b/lib/Doctrine/Query/Offset.php new file mode 100644 index 000000000..fecee7e17 --- /dev/null +++ b/lib/Doctrine/Query/Offset.php @@ -0,0 +1,41 @@ +. + */ + +/** + * Doctrine_Query_Offset + * + * @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: 1352 $ + * @author Konsta Vesterinen + */ +class Doctrine_Query_Offset extends Doctrine_Query_Part +{ + public function parse($offset) + { + $this->query->setQueryPart('offset', (int) $offset); + + return $this->query; + } +} diff --git a/lib/Doctrine/Query/Orderby.php b/lib/Doctrine/Query/Orderby.php index fa363a874..686405b06 100644 --- a/lib/Doctrine/Query/Orderby.php +++ b/lib/Doctrine/Query/Orderby.php @@ -39,7 +39,7 @@ class Doctrine_Query_Orderby extends Doctrine_Query_Part * @param string $str * @return void */ - public function parse($str) + public function parse($str, $append = false) { $ret = array(); @@ -53,12 +53,10 @@ class Doctrine_Query_Orderby extends Doctrine_Query_Part $reference = implode('.', $a); $name = end($a); - $this->query->load($reference, false); - $alias = $this->query->getTableAlias($reference); + $map = $this->query->load($reference, false); + $tableAlias = $this->query->getTableAlias($reference); - $tname = $this->query->getTable($alias)->getTableName(); - - $r = $alias . '.' . $field; + $r = $tableAlias . '.' . $field; } else { @@ -72,6 +70,11 @@ class Doctrine_Query_Orderby extends Doctrine_Query_Part $ret[] = $r; } - return implode(', ', $ret); + if ($append) { + $this->query->addQueryPart('orderby', implode(', ', $ret)); + } else { + $this->query->setQueryPart('orderby', implode(', ', $ret)); + } + return $this->query; } } diff --git a/lib/Doctrine/Query/Set.php b/lib/Doctrine/Query/Set.php index 2e7c56831..8817a8a6c 100644 --- a/lib/Doctrine/Query/Set.php +++ b/lib/Doctrine/Query/Set.php @@ -34,11 +34,11 @@ class Doctrine_Query_Set extends Doctrine_Query_Part { public function parse($dql) { - $parts = Doctrine_Query::sqlExplode($dql, ','); + $parts = Doctrine_Tokenizer::sqlExplode($dql, ','); $result = array(); foreach ($parts as $part) { - $set = Doctrine_Query::sqlExplode($part, '='); + $set = Doctrine_Tokenizer::sqlExplode($part, '='); $e = explode('.', trim($set[0])); $field = array_pop($e); @@ -46,12 +46,15 @@ class Doctrine_Query_Set extends Doctrine_Query_Part $reference = implode('.', $e); $alias = $this->query->getTableAlias($reference); - $table = $this->query->getTable($alias); - $result[] = $table->getColumnName($field) . ' = ' . $set[1]; + $map = $this->query->getDeclaration($reference); + + $result[] = $map['table']->getColumnName($field) . ' = ' . $set[1]; } - return implode(', ', $result); + $this->query->addQueryPart('set', implode(', ', $result)); + + return $this->query; } } diff --git a/lib/Doctrine/Query/Where.php b/lib/Doctrine/Query/Where.php index 3ce934514..91f6a773e 100644 --- a/lib/Doctrine/Query/Where.php +++ b/lib/Doctrine/Query/Where.php @@ -32,6 +32,15 @@ Doctrine::autoload('Doctrine_Query_Condition'); */ class Doctrine_Query_Where extends Doctrine_Query_Condition { + public function parse($str, $append = false) + { + if ($append) { + $this->query->addQueryPart('where', $this->_parse($str)); + } else { + $this->query->setQueryPart('where', $this->_parse($str)); + } + return $this->query; + } /** * load * returns the parsed query part @@ -43,7 +52,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition { $where = trim($where); - $e = Doctrine_Query::sqlExplode($where); + $e = Doctrine_Tokenizer::sqlExplode($where); if (count($e) > 1) { $tmp = $e[0] . ' ' . $e[1]; @@ -56,7 +65,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition } if (count($e) < 3) { - $e = Doctrine_Query::sqlExplode($where, array('=', '<', '>', '!=')); + $e = Doctrine_Tokenizer::sqlExplode($where, array('=', '<', '>', '!=')); } $r = array_shift($e); @@ -83,7 +92,6 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition $field = array_pop($a); $reference = implode('.', $a); $table = $this->query->load($reference, false); - $field = $table->getColumnName($field); array_pop($a); @@ -119,20 +127,20 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition throw new Doctrine_Query_Exception('Unknown DQL function: '.$func); } } else { - $table = $this->query->load($reference, false); - $alias = $this->query->getTableAlias($reference); - $table = $this->query->getTable($alias); - - $field = $table->getColumnName($field); + $map = $this->query->load($reference, false); + + $alias = $this->query->getTableAlias($reference); + $table = $map['table']; + + $field = $table->getColumnName($field); // check if value is enumerated value $enumIndex = $table->enumIndex($field, trim($value, "'")); if (substr($value, 0, 1) == '(') { // trim brackets - $trimmed = Doctrine_Query::bracketTrim($value); + $trimmed = Doctrine_Tokenizer::bracketTrim($value); if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') { - // subquery found $q = new Doctrine_Query(); $value = '(' . $q->isSubquery(true)->parseQuery($trimmed)->getQuery() . ')'; @@ -141,11 +149,12 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition $value = '(' . substr($trimmed, 4) . ')'; } else { // simple in expression found - $e = Doctrine_Query::sqlExplode($trimmed, ','); + $e = Doctrine_Tokenizer::sqlExplode($trimmed, ','); $value = array(); foreach ($e as $part) { - $index = $table->enumIndex($field, trim($part, "'")); + $index = $table->enumIndex($field, trim($part, "'")); + if ($index !== false) { $value[] = $index; } else { @@ -198,10 +207,11 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition $pos = strpos($where, '('); - if ($pos == false) + if ($pos == false) { throw new Doctrine_Query_Exception("Unknown expression, expected '('"); + } - $sub = Doctrine_Query::bracketTrim(substr($where, $pos)); + $sub = Doctrine_Tokenizer::bracketTrim(substr($where, $pos)); return $operator . ' (' . $this->query->createSubquery()->parseQuery($sub, false)->getQuery() . ')'; } @@ -226,14 +236,4 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition } return $operator; } - /** - * __toString - * return string representation of this object - * - * @return string - */ - public function __toString() - { - return ( ! empty($this->parts))?implode(' AND ', $this->parts):''; - } } diff --git a/lib/Doctrine/Record/Filter.php b/lib/Doctrine/Record/Filter.php index 35fe861bb..56604fb33 100644 --- a/lib/Doctrine/Record/Filter.php +++ b/lib/Doctrine/Record/Filter.php @@ -53,7 +53,7 @@ class Doctrine_Record_Filter */ public function getRecord() { - return $this->_record; + return $this->_record; } /** * cleanData @@ -100,8 +100,9 @@ class Doctrine_Record_Filter if (is_string($tmp[$name])) { $value = unserialize($tmp[$name]); - if ($value === false) + if ($value === false) { throw new Doctrine_Record_Exception('Unserialization of ' . $name . ' failed.'); + } } else { $value = $tmp[$name]; } @@ -112,9 +113,10 @@ class Doctrine_Record_Filter if ($tmp[$name] !== self::$null) { $value = gzuncompress($tmp[$name]); - if ($value === false) + if ($value === false) { throw new Doctrine_Record_Exception('Uncompressing of ' . $name . ' failed.'); - + } + $this->_data[$name] = $value; } break; @@ -212,8 +214,9 @@ class Doctrine_Record_Filter $a[$v] = $this->_table->enumIndex($v,$this->_data[$v]); break; default: - if ($this->_data[$v] instanceof Doctrine_Record) + if ($this->_data[$v] instanceof Doctrine_Record) { $this->_data[$v] = $this->_data[$v]->getIncremented(); + } $a[$v] = $this->_data[$v]; } diff --git a/lib/Doctrine/Relation/Association.php b/lib/Doctrine/Relation/Association.php index 8c8c7f451..9ce46a8ff 100644 --- a/lib/Doctrine/Relation/Association.php +++ b/lib/Doctrine/Relation/Association.php @@ -126,7 +126,7 @@ class Doctrine_Relation_Association extends Doctrine_Relation */ public function fetchRelatedFor(Doctrine_Record $record) { - $id = $record->getIncremented(); + $id = $record->getIncremented(); if (empty($id)) { $coll = new Doctrine_Collection($this->getTable()); } else { diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index fc9de5141..44b5cd30e 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -792,7 +792,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $alias = $name; } - $this->bound[$alias] = array('field' => $field, + $this->bound[$alias] = array('field' => $field, 'type' => $type, 'class' => $name, 'alias' => $alias); @@ -1125,32 +1125,38 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable */ public function getRecord() { - $this->data = array_change_key_case($this->data, CASE_LOWER); - - $key = $this->getIdentifier(); - - if ( ! is_array($key)) { - $key = array($key); - } - - foreach ($key as $k) { - if ( ! isset($this->data[$k])) { - throw new Doctrine_Table_Exception("Primary key value for $k wasn't found"); + if ( ! empty($this->data)) { + $this->data = array_change_key_case($this->data, CASE_LOWER); + + $key = $this->getIdentifier(); + + if ( ! is_array($key)) { + $key = array($key); } - $id[] = $this->data[$k]; - } - - $id = implode(' ', $id); - - if (isset($this->identityMap[$id])) { - $record = $this->identityMap[$id]; - $record->hydrate($this->data); + + foreach ($key as $k) { + if ( ! isset($this->data[$k])) { + throw new Doctrine_Table_Exception("Primary key value for $k wasn't found"); + } + $id[] = $this->data[$k]; + } + + $id = implode(' ', $id); + + if (isset($this->identityMap[$id])) { + $record = $this->identityMap[$id]; + $record->hydrate($this->data); + } else { + $recordName = $this->getClassnameToReturn(); + $record = new $recordName($this); + $this->identityMap[$id] = $record; + } + $this->data = array(); } else { $recordName = $this->getClassnameToReturn(); - $record = new $recordName($this); - $this->identityMap[$id] = $record; + $record = new $recordName($this, true); } - $this->data = array(); + return $record; } diff --git a/tests/HydrateTestCase.php b/tests/HydrateTestCase.php index 7067e00ae..e9293260e 100644 --- a/tests/HydrateTestCase.php +++ b/tests/HydrateTestCase.php @@ -111,7 +111,7 @@ class Doctrine_Hydrate_TestCase extends Doctrine_UnitTestCase } */ } -class Doctrine_Hydrate_Mock extends Doctrine_Hydrate2 +class Doctrine_Hydrate_Mock extends Doctrine_Hydrate { protected $data; diff --git a/tests/Query/AggregateValueTestCase.php b/tests/Query/AggregateValueTestCase.php index c2501b214..d88b6eebd 100644 --- a/tests/Query/AggregateValueTestCase.php +++ b/tests/Query/AggregateValueTestCase.php @@ -77,7 +77,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase } public function testAggregateValueIsMappedToNewRecordOnEmptyResultSet() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('COUNT(u.id) count')->from('User u'); @@ -88,7 +88,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase } public function testAggregateValueIsMappedToRecord() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, COUNT(u.id) count')->from('User u')->groupby('u.name'); @@ -105,7 +105,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase public function testAggregateValueMappingSupportsLeftJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, COUNT(p.id) count')->from('User u')->leftJoin('u.Phonenumber p')->groupby('u.id'); @@ -120,7 +120,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase } public function testAggregateValueMappingSupportsLeftJoins2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('MAX(u.name)')->from('User u')->leftJoin('u.Phonenumber p')->groupby('u.id'); @@ -131,7 +131,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase } public function testAggregateValueMappingSupportsMultipleValues() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, COUNT(p.id) count, MAX(p.id) max')->from('User u')->innerJoin('u.Phonenumber p')->groupby('u.id'); @@ -141,7 +141,7 @@ class Doctrine_Query_AggregateValue_TestCase extends Doctrine_UnitTestCase } public function testAggregateValueMappingSupportsInnerJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, COUNT(p.id) count')->from('User u')->innerJoin('u.Phonenumber p')->groupby('u.id'); diff --git a/tests/Query/DeleteTestCase.php b/tests/Query/DeleteTestCase.php index 823b343a7..67e207a16 100644 --- a/tests/Query/DeleteTestCase.php +++ b/tests/Query/DeleteTestCase.php @@ -35,13 +35,13 @@ class Doctrine_Query_Delete_TestCase extends Doctrine_UnitTestCase { public function testDeleteAllWithColumnAggregationInheritance() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('DELETE FROM User'); $this->assertEqual($q->getQuery(), 'DELETE FROM entity WHERE (type = 0)'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->delete()->from('User'); @@ -49,13 +49,13 @@ class Doctrine_Query_Delete_TestCase extends Doctrine_UnitTestCase } public function testDeleteAll() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('DELETE FROM Entity'); $this->assertEqual($q->getQuery(), 'DELETE FROM entity'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->delete()->from('Entity'); @@ -63,13 +63,13 @@ class Doctrine_Query_Delete_TestCase extends Doctrine_UnitTestCase } public function testDeleteWithCondition() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('DELETE FROM Entity WHERE id = 3'); $this->assertEqual($q->getQuery(), 'DELETE FROM entity WHERE id = 3'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->delete()->from('Entity')->where('id = 3'); @@ -77,13 +77,13 @@ class Doctrine_Query_Delete_TestCase extends Doctrine_UnitTestCase } public function testDeleteWithLimit() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('DELETE FROM Entity LIMIT 20'); $this->assertEqual($q->getQuery(), 'DELETE FROM entity LIMIT 20'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->delete()->from('Entity')->limit(20); @@ -91,13 +91,13 @@ class Doctrine_Query_Delete_TestCase extends Doctrine_UnitTestCase } public function testDeleteWithLimitAndOffset() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('DELETE FROM Entity LIMIT 10 OFFSET 20'); $this->assertEqual($q->getQuery(), 'DELETE FROM entity LIMIT 10 OFFSET 20'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->delete()->from('Entity')->limit(10)->offset(20); diff --git a/tests/Query/FromTestCase.php b/tests/Query/FromTestCase.php index 83aad04b7..0785387a0 100644 --- a/tests/Query/FromTestCase.php +++ b/tests/Query/FromTestCase.php @@ -34,7 +34,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase { public function testLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u LEFT JOIN u.Group'); @@ -43,7 +43,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase public function testDefaultJoinIsLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u JOIN u.Group'); @@ -52,7 +52,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase public function testInnerJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u INNER JOIN u.Group'); @@ -61,7 +61,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase public function testMultipleLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u LEFT JOIN u.Group LEFT JOIN u.Phonenumber'); @@ -69,7 +69,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase } public function testMultipleLeftJoin2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u LEFT JOIN u.Group LEFT JOIN u.Phonenumber'); @@ -77,7 +77,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase } public function testMultipleInnerJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name')->from('User u INNER JOIN u.Group INNER JOIN u.Phonenumber'); @@ -85,7 +85,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase } public function testMultipleInnerJoin2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name')->from('User u INNER JOIN u.Group, u.Phonenumber'); @@ -97,7 +97,7 @@ class Doctrine_Query_From_TestCase extends Doctrine_UnitTestCase } public function testMixingOfJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, g.name, p.phonenumber')->from('User u INNER JOIN u.Group g LEFT JOIN u.Phonenumber p'); diff --git a/tests/Query/HavingTestCase.php b/tests/Query/HavingTestCase.php index 61228a205..bfd12179c 100644 --- a/tests/Query/HavingTestCase.php +++ b/tests/Query/HavingTestCase.php @@ -32,14 +32,14 @@ */ class Doctrine_Query_Having_TestCase extends Doctrine_UnitTestCase { public function testAggregateFunctionsInHavingReturnValidSql() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.name FROM User u LEFT JOIN u.Phonenumber p HAVING COUNT(p.id) > 2'); $this->assertEqual($q->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.type = 0) HAVING COUNT(p.id) > 2'); } public function testAggregateFunctionsInHavingReturnValidSql2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name FROM User u LEFT JOIN u.Phonenumber p HAVING MAX(u.name) = 'zYne'"); diff --git a/tests/Query/IdentifierQuotingTestCase.php b/tests/Query/IdentifierQuotingTestCase.php index 30244e518..1620d1e6a 100644 --- a/tests/Query/IdentifierQuotingTestCase.php +++ b/tests/Query/IdentifierQuotingTestCase.php @@ -39,7 +39,7 @@ class Doctrine_Query_IdentifierQuoting_TestCase extends Doctrine_UnitTestCase { public function testQuerySupportsIdentifierQuoting() { $this->connection->setAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER, true); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT MAX(u.id), MIN(u.name) FROM User u'); @@ -47,7 +47,7 @@ class Doctrine_Query_IdentifierQuoting_TestCase extends Doctrine_UnitTestCase { } public function testQuerySupportsIdentifierQuotingWithJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.name FROM User u LEFT JOIN u.Phonenumber p'); @@ -55,7 +55,7 @@ class Doctrine_Query_IdentifierQuoting_TestCase extends Doctrine_UnitTestCase { } public function testLimitSubqueryAlgorithmSupportsIdentifierQuoting() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.name FROM User u INNER JOIN u.Phonenumber p')->limit(5); diff --git a/tests/Query/JoinConditionTestCase.php b/tests/Query/JoinConditionTestCase.php index fa7a8ef25..823fa8203 100644 --- a/tests/Query/JoinConditionTestCase.php +++ b/tests/Query/JoinConditionTestCase.php @@ -38,7 +38,7 @@ class Doctrine_Query_JoinCondition_TestCase extends Doctrine_UnitTestCase { } public function testJoinConditionsAreSupportedForOneToManyLeftJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, p.id FROM User u LEFT JOIN u.Phonenumber p ON p.phonenumber = '123 123'"); @@ -46,7 +46,7 @@ class Doctrine_Query_JoinCondition_TestCase extends Doctrine_UnitTestCase } public function testJoinConditionsAreSupportedForOneToManyInnerJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, p.id FROM User u INNER JOIN u.Phonenumber p ON p.phonenumber = '123 123'"); @@ -54,7 +54,7 @@ class Doctrine_Query_JoinCondition_TestCase extends Doctrine_UnitTestCase } public function testJoinConditionsAreSupportedForManyToManyLeftJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, g.id FROM User u LEFT JOIN u.Group g ON g.id > 2"); @@ -62,7 +62,7 @@ class Doctrine_Query_JoinCondition_TestCase extends Doctrine_UnitTestCase } public function testJoinConditionsAreSupportedForManyToManyInnerJoins() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, g.id FROM User u INNER JOIN u.Group g ON g.id > 2"); diff --git a/tests/Query/JoinTestCase.php b/tests/Query/JoinTestCase.php index d60e6abc6..4ff321317 100644 --- a/tests/Query/JoinTestCase.php +++ b/tests/Query/JoinTestCase.php @@ -58,7 +58,7 @@ class Doctrine_Query_Join_TestCase extends Doctrine_UnitTestCase } public function testRecordHydrationWorksWithDeeplyNestedStructures() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('c.*, c2.*, d.*') ->from('Record_Country c')->leftJoin('c.City c2')->leftJoin('c2.District d') @@ -77,7 +77,7 @@ class Doctrine_Query_Join_TestCase extends Doctrine_UnitTestCase } public function testManyToManyJoinUsesProperTableAliases() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name')->from('User u INNER JOIN u.Group g'); @@ -86,7 +86,7 @@ class Doctrine_Query_Join_TestCase extends Doctrine_UnitTestCase public function testSelfReferentialAssociationJoinsAreSupported() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('e.name')->from('Entity e INNER JOIN e.Entity e2'); diff --git a/tests/Query/LimitTestCase.php b/tests/Query/LimitTestCase.php index f8af6cf6b..227dcdb4a 100644 --- a/tests/Query/LimitTestCase.php +++ b/tests/Query/LimitTestCase.php @@ -45,7 +45,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithOneToOneLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, e.*')->from('User u, u.Email e')->limit(5); $users = $q->execute(); @@ -55,7 +55,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase } public function testLimitWithOneToOneInnerJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, e.*')->from('User u, u:Email e')->limit(5); $users = $q->execute(); @@ -64,7 +64,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase } public function testLimitWithOneToManyLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, p.*')->from('User u, u.Phonenumber p')->limit(5); $sql = $q->getQuery(); @@ -91,7 +91,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithOneToManyLeftJoinAndCondition() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.name')->from('User')->where("User.Phonenumber.phonenumber LIKE '%123%'")->limit(5); $users = $q->execute(); @@ -111,7 +111,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithOneToManyLeftJoinAndOrderBy() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.name')->from('User')->where("User.Phonenumber.phonenumber LIKE '%123%'")->orderby('User.Email.address')->limit(5); @@ -128,7 +128,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithOneToManyInnerJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, p.*')->from('User u INNER JOIN u.Phonenumber p'); $q->limit(5); @@ -156,7 +156,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithPreparedQueries() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, p.id')->from('User u LEFT JOIN u.Phonenumber p'); $q->where('u.name = ?'); $q->limit(5); @@ -170,7 +170,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase $this->assertEqual($q->getQuery(), 'SELECT e.id AS e__id, p.id AS p__id FROM entity e LEFT JOIN phonenumber p ON e.id = p.entity_id WHERE e.id IN (SELECT DISTINCT e2.id FROM entity e2 WHERE e2.name = ? AND (e2.type = 0) LIMIT 5) AND e.name = ? AND (e.type = 0)'); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.id, p.id')->from('User u LEFT JOIN u.Phonenumber p'); $q->where("u.name LIKE ? || u.name LIKE ?"); $q->limit(5); @@ -188,7 +188,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase } public function testConnectionFlushing() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User.Phonenumber'); $q->where('User.name = ?'); $q->limit(5); @@ -200,7 +200,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase } public function testLimitWithManyToManyColumnAggInheritanceLeftJoin() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User.Group')->limit(5); $users = $q->execute(); @@ -227,7 +227,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from("User")->where("User.Group.id = ?")->orderby("User.id ASC")->limit(5); @@ -236,7 +236,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase $this->assertEqual($users->count(), 3); $this->connection->clear(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User')->where('User.Group.id = ?')->orderby('User.id DESC'); $users = $q->execute(array($user->Group[1]->id)); @@ -248,7 +248,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase $this->manager->setAttribute(Doctrine::ATTR_QUERY_LIMIT, Doctrine::LIMIT_ROWS); $this->connection->clear(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from("User")->where("User.Group.id = ?")->orderby("User.id DESC")->limit(5); $users = $q->execute(array(3)); @@ -260,7 +260,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase public function testLimitWithManyToManyAndColumnAggregationInheritance() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u, u.Group g')->where('g.id > 1')->orderby('u.name DESC')->limit(10); } @@ -279,7 +279,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase $coll[3]->name = "photo 4"; $this->connection->flush(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from("Photo")->where("Photo.Tag.id = ?")->orderby("Photo.id DESC")->limit(100); $photos = $q->execute(array(1)); diff --git a/tests/Query/OrderbyTestCase.php b/tests/Query/OrderbyTestCase.php index 1fda9a3b5..468b96913 100644 --- a/tests/Query/OrderbyTestCase.php +++ b/tests/Query/OrderbyTestCase.php @@ -34,7 +34,7 @@ class Doctrine_Query_Orderby_TestCase extends Doctrine_UnitTestCase { public function testOrderByAggregateValueIsSupported() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, COUNT(p.phonenumber) count') ->from('User u') @@ -45,7 +45,7 @@ class Doctrine_Query_Orderby_TestCase extends Doctrine_UnitTestCase } public function testOrderByRandomIsSupported() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('u.name, RANDOM() rand') ->from('User u') diff --git a/tests/Query/SelectTestCase.php b/tests/Query/SelectTestCase.php index cb657a2ce..a91765bd6 100644 --- a/tests/Query/SelectTestCase.php +++ b/tests/Query/SelectTestCase.php @@ -34,7 +34,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase { public function testAggregateFunctionWithDistinctKeyword() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT COUNT(DISTINCT u.name) FROM User u'); @@ -43,7 +43,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase public function testAggregateFunction() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT COUNT(u.id) FROM User u'); @@ -52,7 +52,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase public function testSelectPartSupportsMultipleAggregateFunctions() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT MAX(u.id), MIN(u.name) FROM User u'); @@ -60,7 +60,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testMultipleAggregateFunctionsWithMultipleComponents() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT MAX(u.id), MIN(u.name), COUNT(p.id) FROM User u, u.Phonenumber p'); @@ -68,7 +68,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testEmptySelectPart() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); try { $q->select(null); @@ -80,7 +80,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testUnknownAggregateFunction() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); try { $q->parseQuery('SELECT UNKNOWN(u.id) FROM User'); @@ -91,7 +91,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testAggregateFunctionValueHydration() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.id, COUNT(p.id) FROM User u, u.Phonenumber p GROUP BY u.id'); @@ -107,7 +107,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase public function testSingleComponentWithAsterisk() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.* FROM User u'); @@ -115,7 +115,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testSingleComponentWithMultipleColumns() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.name, u.type FROM User u'); @@ -123,7 +123,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testMultipleComponentsWithAsterisk() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.*, p.* FROM User u, u.Phonenumber p'); @@ -131,7 +131,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testMultipleComponentsWithMultipleColumns() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.id, u.name, p.id FROM User u, u.Phonenumber p'); @@ -140,7 +140,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase public function testAggregateFunctionValueHydrationWithAliases() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.id, COUNT(p.id) count FROM User u, u.Phonenumber p GROUP BY u.id'); @@ -154,7 +154,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase } public function testMultipleAggregateFunctionValueHydrationWithAliases() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.id, COUNT(p.id) count, MAX(p.phonenumber) max FROM User u, u.Phonenumber p GROUP BY u.id'); @@ -175,7 +175,7 @@ class Doctrine_Query_Select_TestCase extends Doctrine_UnitTestCase { $this->connection->clear(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery('SELECT u.id, COUNT(p.id) count, MAX(p.phonenumber) max FROM User u, u.Phonenumber p GROUP BY u.id'); diff --git a/tests/Query/SubqueryTestCase.php b/tests/Query/SubqueryTestCase.php index c02626325..03b15ee89 100644 --- a/tests/Query/SubqueryTestCase.php +++ b/tests/Query/SubqueryTestCase.php @@ -36,7 +36,7 @@ class Doctrine_Query_Subquery_TestCase extends Doctrine_UnitTestCase public function testSubqueryWithWherePartAndInExpression() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User')->where("User.id NOT IN (SELECT User.id FROM User WHERE User.name = 'zYne')"); $this->assertEqual($q->getQuery(), @@ -49,7 +49,7 @@ class Doctrine_Query_Subquery_TestCase extends Doctrine_UnitTestCase } public function testSubqueryAllowsSelectingOfAnyField() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u')->where('u.id NOT IN (SELECT g.user_id FROM Groupuser g)'); $this->assertEqual($q->getQuery(), "SELECT e.id AS e__id, e.name AS e__name, e.loginname AS e__loginname, e.password AS e__password, e.type AS e__type, e.created AS e__created, e.updated AS e__updated, e.email_id AS e__email_id FROM entity e WHERE e.id NOT IN (SELECT g.user_id AS g__user_id FROM groupuser g) AND (e.type = 0)"); @@ -58,7 +58,7 @@ class Doctrine_Query_Subquery_TestCase extends Doctrine_UnitTestCase public function testSubqueryInSelectPart() { // ticket #307 - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, (SELECT COUNT(p.id) FROM Phonenumber p WHERE p.entity_id = u.id) pcount FROM User u WHERE u.name = 'zYne' LIMIT 1"); @@ -77,7 +77,7 @@ class Doctrine_Query_Subquery_TestCase extends Doctrine_UnitTestCase public function testSubqueryInSelectPart2() { // ticket #307 - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("SELECT u.name, (SELECT COUNT(w.id) FROM User w WHERE w.id = u.id) pcount FROM User u WHERE u.name = 'zYne' LIMIT 1"); diff --git a/tests/Query/UpdateTestCase.php b/tests/Query/UpdateTestCase.php index 10d2b7821..ef3f6a42d 100644 --- a/tests/Query/UpdateTestCase.php +++ b/tests/Query/UpdateTestCase.php @@ -35,13 +35,13 @@ class Doctrine_Query_Update_TestCase extends Doctrine_UnitTestCase { public function testUpdateAllWithColumnAggregationInheritance() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("UPDATE User u SET u.name = 'someone'"); $this->assertEqual($q->getQuery(), "UPDATE entity SET name = 'someone' WHERE (type = 0)"); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->update('User u')->set('u.name', "'someone'"); @@ -49,13 +49,13 @@ class Doctrine_Query_Update_TestCase extends Doctrine_UnitTestCase } public function testUpdateWorksWithMultipleColumns() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("UPDATE User u SET u.name = 'someone', u.email_id = 5"); $this->assertEqual($q->getQuery(), "UPDATE entity SET name = 'someone', email_id = 5 WHERE (type = 0)"); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->update('User u')->set('u.name', "'someone'")->set('u.email_id', 5); @@ -63,7 +63,7 @@ class Doctrine_Query_Update_TestCase extends Doctrine_UnitTestCase } public function testUpdateSupportsConditions() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->parseQuery("UPDATE User u SET u.name = 'someone' WHERE u.id = 5"); diff --git a/tests/Query/WhereTestCase.php b/tests/Query/WhereTestCase.php index b8ffb86be..02ea8fe96 100644 --- a/tests/Query/WhereTestCase.php +++ b/tests/Query/WhereTestCase.php @@ -47,7 +47,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase $user->name = 'someone'; $user->save(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User')->addWhere('User.id = ?',1); @@ -63,7 +63,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase $user->name = 'someone.2'; $user->save(); - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User')->addWhere('User.id IN (?, ?)', array(1, 2)); @@ -75,7 +75,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testDirectMultipleParameterSetting2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User')->where('User.id IN (?, ?)', array(1, 2)); @@ -98,7 +98,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testNotInExpression() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u')->addWhere('u.id NOT IN (?)', array(1)); $users = $q->execute(); @@ -108,7 +108,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testExistsExpression() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $user = new User(); $user->name = 'someone with a group'; @@ -129,7 +129,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase public function testNotExistsExpression() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); // find all users which don't have groups try { @@ -145,7 +145,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testComponentAliases() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u')->addWhere('u.id IN (?, ?)', array(1,2)); @@ -158,7 +158,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testComponentAliases2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->from('User u')->addWhere('u.name = ?', array('someone')); @@ -169,7 +169,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testOperatorWithNoTrailingSpaces() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.id')->from('User')->where("User.name='someone'"); @@ -180,7 +180,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testOperatorWithNoTrailingSpaces2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.id')->from('User')->where("User.name='foo.bar'"); @@ -191,7 +191,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testOperatorWithSingleTrailingSpace() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.id')->from('User')->where("User.name= 'foo.bar'"); @@ -202,7 +202,7 @@ class Doctrine_Query_Where_TestCase extends Doctrine_UnitTestCase } public function testOperatorWithSingleTrailingSpace2() { - $q = new Doctrine_Query2(); + $q = new Doctrine_Query(); $q->select('User.id')->from('User')->where("User.name ='foo.bar'");