diff --git a/CHANGELOG b/CHANGELOG index ffbb36e04..21694ee89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ Beta 2 ------ +* r3183: NestedSet: 'level' column renamed to 'lvl' because LEVEL is an oracle keyword. + In order to upgrade existing trees you need to rename the level column to lvl + in your databases. This does not affect your code because the NestedSet now uses + a column alias (lvl as level). So your code still refers to the 'level' field. * r3048: Doctrine::exportSchema() replaced by Doctrine::createTablesFromModels() * r3048: Doctrine::exportSql() replaced by Doctrine::generateSqlFromModels() * r3048: Doctrine::importSchema() replaced by Doctrine::generateModelsFromDb() diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index b9f51d5a3..e2b6a16b4 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -151,7 +151,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun protected $options = array(); /** - * @var array $availableDrivers an array containing all availible drivers + * @var array $availableDrivers an array containing all available drivers */ private static $availableDrivers = array( 'Mysql', @@ -180,7 +180,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $this->isConnected = true; - } elseif (is_array($adapter)) { + } else if (is_array($adapter)) { $this->pendingAttributes[Doctrine::ATTR_DRIVER_NAME] = $adapter['scheme']; $this->options['dsn'] = $adapter['dsn']; @@ -468,7 +468,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * @throws PDOException if something fails at PDO level * @return integer number of rows affected */ - public function replace($table, array $fields, array $keys) + public function replace(Doctrine_Table $table, array $fields, array $keys) { //if ( ! $this->supports('replace')) // throw new Doctrine_Connection_Exception('replace query is not supported'); @@ -478,26 +478,26 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun } $condition = $values = array(); - foreach ($fields as $name => $value) { - $values[$name] = $value; + foreach ($fields as $fieldName => $value) { + $values[$fieldName] = $value; - if (in_array($name, $keys)) { + if (in_array($fieldName, $keys)) { if ($value === null) - throw new Doctrine_Connection_Exception('key value '.$name.' may not be null'); + throw new Doctrine_Connection_Exception('key value '.$fieldName.' may not be null'); - $condition[] = $name . ' = ?'; + $condition[] = $table->getColumnName($fieldName) . ' = ?'; $conditionValues[] = $value; } } - $query = 'DELETE FROM ' . $this->quoteIdentifier($table) . ' WHERE ' . implode(' AND ', $condition); - $affectedRows = $this->exec($query); + $query = 'DELETE FROM ' . $this->quoteIdentifier($table->getTableName()) + . ' WHERE ' . implode(' AND ', $condition); + $affectedRows = $this->exec($query, $conditionValues); $this->insert($table, $values); $affectedRows++; - return $affectedRows; } @@ -509,16 +509,16 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * @param array $identifier An associateve array containing identifier column-value pairs. * @return integer The number of affected rows */ - public function delete($table, array $identifier) + public function delete(Doctrine_Table $table, array $identifier) { $tmp = array(); foreach (array_keys($identifier) as $id) { - $tmp[] = $id . ' = ?'; + $tmp[] = $table->getColumnName($id) . ' = ?'; } $query = 'DELETE FROM ' - . $this->quoteIdentifier($table) + . $this->quoteIdentifier($table->getTableName()) . ' WHERE ' . implode(' AND ', $tmp); @@ -534,27 +534,27 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * @return mixed boolean false if empty value array was given, * otherwise returns the number of affected rows */ - public function update($table, array $values, array $identifier) + public function update(Doctrine_Table $table, array $fields, array $identifier) { - if (empty($values)) { + if (empty($fields)) { return false; } $set = array(); - foreach ($values as $name => $value) { + foreach ($fields as $fieldName => $value) { if ($value instanceof Doctrine_Expression) { - $set[] = $name . ' = ' . $value->getSql(); + $set[] = $table->getColumnName($fieldName) . ' = ' . $value->getSql(); unset($values[$name]); } else { - $set[] = $name . ' = ?'; + $set[] = $table->getColumnName($fieldName) . ' = ?'; } } - $params = array_merge(array_values($values), array_values($identifier)); + $params = array_merge(array_values($fields), array_values($identifier)); - $sql = 'UPDATE ' . $this->quoteIdentifier($table) + $sql = 'UPDATE ' . $this->quoteIdentifier($table->getTableName()) . ' SET ' . implode(', ', $set) - . ' WHERE ' . implode(' = ? AND ', array_keys($identifier)) + . ' WHERE ' . implode(' = ? AND ', $table->getIdentifierColumnNames()) . ' = ?'; return $this->exec($sql, $params); @@ -568,34 +568,36 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * @return mixed boolean false if empty value array was given, * otherwise returns the number of affected rows */ - public function insert($table, array $values) { - if (empty($values)) { + public function insert(Doctrine_Table $table, array $fields) { + if (empty($fields)) { return false; } + $tableName = $table->getTableName(); + // column names are specified as array keys $cols = array(); // the query VALUES will contain either expresions (eg 'NOW()') or ? $a = array(); - foreach ($values as $k => $value) { - $cols[] = $this->quoteIdentifier($k); + foreach ($fields as $fieldName => $value) { + $cols[] = $this->quoteIdentifier($table->getColumnName($fieldName)); if ($value instanceof Doctrine_Expression) { $a[] = $value->getSql(); - unset($values[$k]); + unset($fields[$fieldName]); } else { $a[] = '?'; } } // build the statement - $query = 'INSERT INTO ' . $this->quoteIdentifier($table) + $query = 'INSERT INTO ' . $this->quoteIdentifier($tableName) . ' (' . implode(', ', $cols) . ') ' . 'VALUES ('; $query .= implode(', ', $a) . ')'; // prepare and execute the statement - return $this->exec($query, array_values($values)); + return $this->exec($query, array_values($fields)); } /** @@ -912,6 +914,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $this->getAttribute(Doctrine::ATTR_LISTENER)->preQuery($event); if ( ! $event->skipOperation) { + //echo $query . "
"; $stmt = $this->dbh->query($query); $this->_count++; diff --git a/lib/Doctrine/Connection/Mysql.php b/lib/Doctrine/Connection/Mysql.php index 7e4972f6d..32cd5aa50 100644 --- a/lib/Doctrine/Connection/Mysql.php +++ b/lib/Doctrine/Connection/Mysql.php @@ -166,7 +166,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common * * @return integer the number of affected rows */ - public function replace($table, array $fields, array $keys) + public function replace(Doctrine_Table $table, array $fields, array $keys) { $count = count($fields); $query = $values = ''; @@ -180,7 +180,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common $values.= ','; } - $query .= $name; + $query .= $table->getColumnName($name); if (isset($fields[$name]['null']) && $fields[$name]['null']) { $value = 'NULL'; @@ -202,7 +202,7 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common if ($keys == 0) { throw new Doctrine_Connection_Mysql_Exception('not specified which fields are keys'); } - $query = 'REPLACE INTO ' . $table . ' (' . $query . ') VALUES (' . $values . ')'; + $query = 'REPLACE INTO ' . $table->getTableName() . ' (' . $query . ') VALUES (' . $values . ')'; return $this->exec($query); } diff --git a/lib/Doctrine/Connection/UnitOfWork.php b/lib/Doctrine/Connection/UnitOfWork.php index 364813b8d..5705735e8 100644 --- a/lib/Doctrine/Connection/UnitOfWork.php +++ b/lib/Doctrine/Connection/UnitOfWork.php @@ -148,9 +148,8 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module } $record->state(Doctrine_Record::STATE_LOCKED); - + $conn->beginTransaction(); - $saveLater = $this->saveRelated($record); $record->state($state); @@ -159,7 +158,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $event = new Doctrine_Event($record, Doctrine_Event::RECORD_SAVE); $record->preSave($event); - + $record->getTable()->getRecordListener()->preSave($event); $state = $record->state(); @@ -180,7 +179,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module } $record->getTable()->getRecordListener()->postSave($event); - + $record->postSave($event); } else { $conn->transaction->addInvalid($record); @@ -195,7 +194,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module if ($record->hasReference($alias)) { $obj = $record->$alias; - + // check that the related object is not an instance of Doctrine_Null if ( ! ($obj instanceof Doctrine_Null)) { $obj->save($conn); @@ -207,7 +206,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $this->saveAssociations($record); $record->state($state); - + $conn->commit(); return true; @@ -284,10 +283,10 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module foreach ($table->getOption('joinedParents') as $parent) { $parentTable = $table->getConnection()->getTable($parent); - $this->conn->delete($parentTable->getTableName(), $record->identifier()); + $this->conn->delete($parentTable, $record->identifier()); } } - $this->conn->delete($table->getTableName(), $record->identifier()); + $this->conn->delete($table, $record->identifier()); $record->state(Doctrine_Record::STATE_TCLEAN); } else { @@ -295,7 +294,6 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $record->state($state); } - $table->getRecordListener()->postDelete($event); $record->postDelete($event); @@ -554,12 +552,12 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module foreach ($classes as $class) { $parentTable = $this->conn->getTable($class); - $this->conn->update($this->conn->getTable($class)->getTableName(), $dataSet[$class], $identifier); + $this->conn->update($this->conn->getTable($class), $dataSet[$class], $identifier); } } else { $array = $record->getPrepared(); - $this->conn->update($table->getTableName(), $array, $identifier); + $this->conn->update($table, $array, $identifier); } $record->assignIdentifier(true); } @@ -608,7 +606,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $dataSet[$parent][$id] = $value; } - $this->conn->insert($this->conn->getTable($parent)->getTableName(), $dataSet[$parent]); + $this->conn->insert($this->conn->getTable($parent), $dataSet[$parent]); } } } else { @@ -624,6 +622,10 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module return true; } + + /** + * @todo DESCRIBE WHAT THIS METHOD DOES, PLEASE! + */ public function formatDataSet(Doctrine_Record $record) { $table = $record->getTable(); @@ -634,47 +636,53 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $array = $record->getPrepared(); - foreach ($table->getColumns() as $column => $definition) { + foreach ($table->getColumns() as $columnName => $definition) { + $fieldName = $table->getFieldName($columnName); if (isset($definition['primary']) && $definition['primary']) { continue; } if (isset($definition['owner'])) { - $dataSet[$definition['owner']][$column] = $array[$column]; + $dataSet[$definition['owner']][$fieldName] = $array[$fieldName]; } else { - $dataSet[$component][$column] = $array[$column]; + $dataSet[$component][$fieldName] = $array[$fieldName]; } } return $dataSet; } + + /** + * @todo DESCRIBE WHAT THIS METHOD DOES, PLEASE! + */ public function processSingleInsert(Doctrine_Record $record) { - $array = $record->getPrepared(); + $fields = $record->getPrepared(); - if (empty($array)) { + if (empty($fields)) { return false; } - $table = $record->getTable(); - $keys = (array) $table->getIdentifier(); + + $table = $record->getTable(); + $identifier = (array) $table->getIdentifier(); - $seq = $record->getTable()->sequenceName; + $seq = $record->getTable()->sequenceName; if ( ! empty($seq)) { - $id = $this->conn->sequence->nextId($seq); - $name = $record->getTable()->getIdentifier(); - $array[$name] = $id; + $id = $this->conn->sequence->nextId($seq); + $seqName = $table->getIdentifier(); + $fields[$seqName] = $id; $record->assignIdentifier($id); } - $this->conn->insert($table->getTableName(), $array); + $this->conn->insert($table, $fields); - if (empty($seq) && count($keys) == 1 && $keys[0] == $table->getIdentifier() && + if (empty($seq) && count($identifier) == 1 && $identifier[0] == $table->getIdentifier() && $table->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) { if (strtolower($this->conn->getName()) == 'pgsql') { - $seq = $table->getTableName() . '_' . $keys[0]; + $seq = $table->getTableName() . '_' . $identifier[0]; } $id = $this->conn->sequence->lastInsertId($seq); diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index a327ad446..739870df3 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -819,7 +819,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab if ($this->type !== self::SELECT) { return $this->_conn->exec($query, $params); } - + //echo $query . "

"; $stmt = $this->_conn->execute($query, $params); return $stmt; } @@ -850,7 +850,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab if ($cached === false) { // cache miss $stmt = $this->_execute($params); - $array = $this->parseData2($stmt, Doctrine::HYDRATE_ARRAY); + $array = $this->hydrateResultSet($stmt, Doctrine::HYDRATE_ARRAY); $cached = $this->getCachedForm($array); @@ -883,7 +883,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab return $stmt; } - $array = $this->parseData2($stmt, $hydrationMode); + $array = $this->hydrateResultSet($stmt, $hydrationMode); } return $array; } @@ -1022,7 +1022,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab * @param mixed $stmt * @return array */ - public function parseData2($stmt, $hydrationMode) + public function hydrateResultSet($stmt, $hydrationMode) { if ($hydrationMode == Doctrine::HYDRATE_NONE) { return $stmt->fetchAll(PDO::FETCH_NUM); @@ -1076,29 +1076,33 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab // of magnitude. if ( ! isset($cache[$key])) { $e = explode('__', $key); - $cache[$key]['field'] = $field = strtolower(array_pop($e)); + $last = strtolower(array_pop($e)); $cache[$key]['alias'] = $this->_tableAliases[strtolower(implode('__', $e))]; + $fieldName = $this->_aliasMap[$cache[$key]['alias']]['table']->getFieldName($last); + //echo "hydrate:" . $fieldName . "

"; + $cache[$key]['fieldName'] = $fieldName; + $cache[$key]['columnName'] = $last; } $map = $this->_aliasMap[$cache[$key]['alias']]; $table = $map['table']; $alias = $cache[$key]['alias']; - $field = $cache[$key]['field']; + $fieldName = $cache[$key]['fieldName']; - if (isset($this->_aliasMap[$alias]['agg'][$field])) { - $field = $this->_aliasMap[$alias]['agg'][$field]; + if (isset($this->_aliasMap[$alias]['agg'][$fieldName])) { + $fieldName = $this->_aliasMap[$alias]['agg'][$fieldName]; } - - if ($table->isIdentifier($field)) { + if ($table->isIdentifier($fieldName)) { $id[$alias] .= '|' . $value; } - $currData[$alias][$field] = $table->prepareValue($field, $value); + $currData[$alias][$fieldName] = $table->prepareValue($fieldName, $value); if ($value !== null) { $identifiable[$alias] = true; } + } // dealing with root component @@ -1162,7 +1166,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab if ( ! isset($prev[$parent])) { break; } - + // check the type of the relation if ( ! $relation->isOneToOne()) { // initialize the collection @@ -1207,7 +1211,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab } else { $prev[$parent][$componentAlias] = $element; } - $oneToOne = true; + $oneToOne = true; } $coll =& $prev[$parent][$componentAlias]; $this->_setLastElement($prev, $coll, $index, $alias, $oneToOne); @@ -1215,7 +1219,7 @@ class Doctrine_Hydrate extends Doctrine_Locator_Injectable implements Serializab } $id[$rootAlias] = ''; } - + $driver->flush(); $stmt->closeCursor(); diff --git a/lib/Doctrine/Hydrate/Record.php b/lib/Doctrine/Hydrate/Record.php index 1a737fcb3..2471195f7 100644 --- a/lib/Doctrine/Hydrate/Record.php +++ b/lib/Doctrine/Hydrate/Record.php @@ -78,7 +78,7 @@ class Doctrine_Hydrate_Record extends Doctrine_Locator_Injectable */ public function isIdentifiable(array $row, Doctrine_Table $table) { - $primaryKeys = $table->getIdentifier(); + $primaryKeys = $table->getIdentifierColumnNames(); if (is_array($primaryKeys)) { foreach ($primaryKeys as $id) { @@ -103,8 +103,15 @@ class Doctrine_Hydrate_Record extends Doctrine_Locator_Injectable $this->_tables[$component] = Doctrine_Manager::getInstance()->getTable($component); $this->_tables[$component]->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, false); } + + //echo "..before.."; + //Doctrine::dump($data); + $this->_tables[$component]->setData($data); $record = $this->_tables[$component]->getRecord(); + + //echo "..after.."; + //Doctrine::dump($record->getData()); if ( ! isset($this->_records[$record->getOid()]) ) { $record->clearRelated(); diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index e7948916e..91ec8453c 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -32,6 +32,7 @@ Doctrine::autoload('Doctrine_Query_Abstract'); */ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable { + /** @todo document the query states (and the transitions between them). */ const STATE_CLEAN = 1; const STATE_DIRTY = 2; @@ -156,7 +157,10 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable protected $_pendingJoinConditions = array(); protected $_expressionMap = array(); - + + /** + * @var integer $_state The current state of this query. + */ protected $_state = Doctrine_Query::STATE_CLEAN; /** @@ -170,7 +174,10 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable { return new Doctrine_Query($conn); } - + + /** + * Resets the query to the state just after it has been instantiated. + */ public function reset() { $this->_pendingJoinConditions = array(); @@ -318,6 +325,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * * @throws Doctrine_Query_Exception if unknown parser name given * @return Doctrine_Query_Part + * @todo Doc/Description: What is the parameter for? Which parsers are available? */ public function getParser($name) { @@ -386,10 +394,12 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable /** * getDqlPart - * returns the given DQL query part + * returns a specific DQL query part. * * @param string $queryPart the name of the query part * @return string the DQL query part + * @todo Description: List which query parts exist or point to the method/property + * where they are listed. */ public function getDqlPart($queryPart) { @@ -402,7 +412,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable /** * getDql - * returns the DQL query associated with this object + * returns the DQL query that is represented by this query object. * * the query is built from $_dqlParts * @@ -432,6 +442,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * @throws Doctrine_Query_Exception if unknown component alias has been given * @param string $componentAlias the alias of the component * @return void + * @todo Description: What is a 'pending field' (and are there non-pending fields, too)? + * What is 'processed'? (Meaning: What information is gathered & stored away) */ public function processPendingFields($componentAlias) { @@ -443,6 +455,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable // check for wildcards if (in_array('*', $fields)) { + //echo "
";Doctrine::dump($table->getColumnNames()); echo "
"; $fields = $table->getColumnNames(); } else { // only auto-add the primary key fields if this query object is not @@ -477,7 +490,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable } $this->_neededTables[] = $tableAlias; - + //Doctrine::dump(implode(', ', $sql)); + //echo "

"; return implode(', ', $sql); } } @@ -487,6 +501,9 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * * @throws Doctrine_Query_Exception if unknown component alias has been given * @return void + * @todo Description: Explain what this method does. Is there a relation to parseSelect()? + * (It doesnt seem to get called from there...?). In what circumstances is this method + * used? */ public function parseSelectField($field) { @@ -533,6 +550,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * * @param string $expr expression from which to get to owner from * @return string the component alias + * @todo Description: What does it mean if a component is an 'owner' of an expression? + * What kind of 'expression' are we talking about here? */ public function getExpressionOwner($expr) { @@ -557,6 +576,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * adds selected fields to pendingFields array * * @param string $dql + * @todo Description: What information is extracted (and then stored)? */ public function parseSelect($dql) { @@ -640,8 +660,10 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * 5. Parses nested clauses and subqueries recursively * * @return string SQL string + * @todo Description: What is a 'dql clause' (and what not)? + * Refactor: Too long & nesting level */ - public function parseClause($clause) + public function parseClause($clause) { $clause = trim($clause); @@ -670,7 +692,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable // convert DQL function to its RDBMS specific equivalent try { $expr = call_user_func_array(array($this->_conn->expression, $name), $args); - } catch(Doctrine_Expression_Exception $e) { + } catch (Doctrine_Expression_Exception $e) { throw new Doctrine_Query_Exception('Unknown function ' . $expr . '.'); } $term[0] = $expr; @@ -849,6 +871,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * since some subqueries may be correlated * * @return void + * @todo Better description. i.e. What is a 'pending subquery'? What does 'processed' mean? + * (parsed? sql is constructed? some information is gathered?) */ public function processPendingSubqueries() { @@ -878,6 +902,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * processes pending aggregate values for given component alias * * @return void + * @todo Better description. i.e. What is a 'pending aggregate'? What does 'processed' mean? */ public function processPendingAggregates() { @@ -1135,7 +1160,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $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) { $this->isLimitSubqueryUsed = true; $needsSubQuery = true; } @@ -1235,6 +1261,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * of limiting the number of sql result set rows * * @return string the limit subquery + * @todo A little refactor to make the method easier to understand & maybe shorter? */ public function getLimitSubquery() { @@ -1445,7 +1472,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $parts = $this->tokenizeQuery($query); - foreach($parts as $k => $part) { + foreach ($parts as $k => $part) { $part = implode(' ', $part); $k = strtolower($k); switch ($k) { @@ -1485,7 +1512,10 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable return $this; } - + + /** + * @todo DESCRIBE ME! REFACTOR ME! I'M FAR TOO LONG AND COMPLEX! HARD TO UNDERSTAND! + */ public function load($path, $loadFields = true) { if (isset($this->_aliasMap[$path])) { @@ -1610,7 +1640,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $queryPart .= ' ON ' . $localAlias . '.' - . $localTable->getIdentifier() + . $localTable->getIdentifier() // what about composite keys? . ' = ' . $assocAlias . '.' . $relation->getLocal(); @@ -1708,6 +1738,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable * * @param string $name * @param string $componentAlias + * @todo DESCRIBE ME! */ public function loadRoot($name, $componentAlias) { @@ -1737,11 +1768,14 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable return $table; } + + /** + * @todo DESCRIBE ME! + */ public function buildInheritanceJoinSql($name, $componentAlias) { // get the connection for the component - $this->_conn = Doctrine_Manager::getInstance() - ->getConnectionForComponent($name); + $this->_conn = Doctrine_Manager::getInstance()->getConnectionForComponent($name); $table = $this->_conn->getTable($name); $tableName = $table->getTableName(); @@ -1762,6 +1796,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $queryPart .= ' LEFT JOIN ' . $this->_conn->quoteIdentifier($parentTable->getTableName()) . ' ' . $this->_conn->quoteIdentifier($parentTableAlias) . ' ON '; + //Doctrine::dump($table->getIdentifier()); foreach ((array) $table->getIdentifier() as $identifier) { $column = $table->getColumnName($identifier); diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 9a0b83dc1..d51d8f562 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -105,7 +105,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count protected $_state; /** - * @var array $_modified an array containing properties that have been modified + * @var array $_modified an array containing field names that have been modified */ protected $_modified = array(); @@ -156,48 +156,47 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count // Check if the current connection has the records table in its registry // If not this record is only used for creating table definition and setting up // relations. + if ( ! $this->_table->getConnection()->hasTable($this->_table->getComponentName())) { + return; + } - if ($this->_table->getConnection()->hasTable($this->_table->getComponentName())) { - $this->_oid = self::$_index; + $this->_oid = self::$_index; - self::$_index++; + self::$_index++; - $keys = (array) $this->_table->getIdentifier(); + // get the data array + $this->_data = $this->_table->getData(); - // get the data array - $this->_data = $this->_table->getData(); + // get the column count + $count = count($this->_data); - // get the column count - $count = count($this->_data); + $this->_values = $this->cleanData($this->_data); - $this->_values = $this->cleanData($this->_data); + $this->prepareIdentifiers($exists); - $this->prepareIdentifiers($exists); - - if ( ! $exists) { - if ($count > count($this->_values)) { - $this->_state = Doctrine_Record::STATE_TDIRTY; - } else { - $this->_state = Doctrine_Record::STATE_TCLEAN; - } - - // set the default values for this record - $this->assignDefaultValues(); + if ( ! $exists) { + if ($count > count($this->_values)) { + $this->_state = Doctrine_Record::STATE_TDIRTY; } else { - $this->_state = Doctrine_Record::STATE_CLEAN; - - if ($count < $this->_table->getColumnCount()) { - $this->_state = Doctrine_Record::STATE_PROXY; - } + $this->_state = Doctrine_Record::STATE_TCLEAN; } - $this->_errorStack = new Doctrine_Validator_ErrorStack(get_class($this)); + // set the default values for this record + $this->assignDefaultValues(); + } else { + $this->_state = Doctrine_Record::STATE_CLEAN; - $repository = $this->_table->getRepository(); - $repository->add($this); - - $this->construct(); + if ($count < $this->_table->getColumnCount()) { + $this->_state = Doctrine_Record::STATE_PROXY; + } } + + $this->_errorStack = new Doctrine_Validator_ErrorStack(get_class($this)); + + $repository = $this->_table->getRepository(); + $repository->add($this); + + $this->construct(); } @@ -434,13 +433,14 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $tmp = $data; $data = array(); - foreach ($this->getTable()->getColumnNames() as $name) { - if ( ! isset($tmp[$name])) { - $data[$name] = self::$_null; + //Doctrine::dump($this->getTable()->getFieldNames()); + foreach ($this->getTable()->getFieldNames() as $fieldName) { + if ( ! isset($tmp[$fieldName])) { + $data[$fieldName] = self::$_null; } else { - $data[$name] = $tmp[$name]; + $data[$fieldName] = $tmp[$fieldName]; } - unset($tmp[$name]); + unset($tmp[$fieldName]); } return $tmp; @@ -455,9 +455,10 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count */ public function hydrate(array $data) { + $this->_values = array_merge($this->_values, $this->cleanData($data)); $this->_data = array_merge($this->_data, $data); - + //Doctrine::dump($this->_data); $this->prepareIdentifiers(true); } @@ -475,7 +476,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count case Doctrine::IDENTIFIER_SEQUENCE: case Doctrine::IDENTIFIER_NATURAL: $name = $this->_table->getIdentifier(); - + if (is_array($name)) { + $name = $name[0]; + } if ($exists) { if (isset($this->_data[$name]) && $this->_data[$name] !== self::$_null) { $this->_id[$name] = $this->_data[$name]; @@ -623,7 +626,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } else { $err = true; } - } elseif (is_string($state)) { + } else if (is_string($state)) { $upper = strtoupper($state); $const = 'Doctrine_Record::STATE_' . $upper; @@ -677,7 +680,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $this->prepareIdentifiers(); - $this->_state = Doctrine_Record::STATE_CLEAN; + $this->_state = Doctrine_Record::STATE_CLEAN; return $this; } @@ -745,15 +748,16 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * @throws Doctrine_Record_Exception if trying to get an unknown property * @return mixed */ - public function rawGet($name) + public function rawGet($fieldName) { - if ( ! isset($this->_data[$name])) { - throw new Doctrine_Record_Exception('Unknown property '. $name); + if ( ! isset($this->_data[$fieldName])) { + throw new Doctrine_Record_Exception('Unknown property '. $fieldName); } - if ($this->_data[$name] === self::$_null) + if ($this->_data[$fieldName] === self::$_null) { return null; + } - return $this->_data[$name]; + return $this->_data[$fieldName]; } /** @@ -767,9 +771,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count // only load the data from database if the Doctrine_Record is in proxy state if ($this->_state == Doctrine_Record::STATE_PROXY) { $this->refresh(); - $this->_state = Doctrine_Record::STATE_CLEAN; - return true; } return false; @@ -784,45 +786,40 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * @throws Doctrine_Record_Exception if trying to get a value of unknown property / related component * @return mixed */ - public function get($name, $load = true) + public function get($fieldName, $load = true) { $value = self::$_null; - $lower = strtolower($name); - $lower = $this->_table->getColumnName($lower); - - if (isset($this->_data[$lower])) { + if (isset($this->_data[$fieldName])) { // check if the property is null (= it is the Doctrine_Null object located in self::$_null) - if ($this->_data[$lower] === self::$_null && $load) { + if ($this->_data[$fieldName] === self::$_null && $load) { $this->load(); } - if ($this->_data[$lower] === self::$_null) { + if ($this->_data[$fieldName] === self::$_null) { $value = null; } else { - $value = $this->_data[$lower]; + $value = $this->_data[$fieldName]; } return $value; } - if (isset($this->_values[$lower])) { - return $this->_values[$lower]; + if (isset($this->_values[$fieldName])) { + return $this->_values[$fieldName]; } try { + if ( ! isset($this->_references[$fieldName]) && $load) { - if ( ! isset($this->_references[$name]) && $load) { + $rel = $this->_table->getRelation($fieldName); - $rel = $this->_table->getRelation($name); - - $this->_references[$name] = $rel->fetchRelatedFor($this); + $this->_references[$fieldName] = $rel->fetchRelatedFor($this); } - return $this->_references[$name]; - - } catch(Doctrine_Table_Exception $e) { + return $this->_references[$fieldName]; + } catch (Doctrine_Table_Exception $e) { foreach ($this->_table->getFilters() as $filter) { - if (($value = $filter->filterGet($this, $name, $value)) !== null) { + if (($value = $filter->filterGet($this, $fieldName, $value)) !== null) { return $value; } } @@ -841,7 +838,6 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count */ public function mapValue($name, $value) { - $name = strtolower($name); $this->_values[$name] = $value; } @@ -859,15 +855,11 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * * @return Doctrine_Record */ - public function set($name, $value, $load = true) + public function set($fieldName, $value, $load = true) { - $lower = strtolower($name); - - $lower = $this->_table->getColumnName($lower); - - if (isset($this->_data[$lower])) { + if (isset($this->_data[$fieldName])) { if ($value instanceof Doctrine_Record) { - $type = $this->_table->getTypeOf($name); + $type = $this->_table->getTypeOf($fieldName); $id = $value->getIncremented(); @@ -877,9 +869,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } if ($load) { - $old = $this->get($lower, $load); + $old = $this->get($fieldName, $load); } else { - $old = $this->_data[$lower]; + $old = $this->_data[$fieldName]; } if ($old !== $value) { @@ -887,8 +879,8 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $value = self::$_null; } - $this->_data[$lower] = $value; - $this->_modified[] = $lower; + $this->_data[$fieldName] = $value; + $this->_modified[] = $fieldName; switch ($this->_state) { case Doctrine_Record::STATE_CLEAN: $this->_state = Doctrine_Record::STATE_DIRTY; @@ -900,17 +892,21 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } } else { try { - $this->coreSetRelated($name, $value); - } catch(Doctrine_Table_Exception $e) { + $this->coreSetRelated($fieldName, $value); + } catch (Doctrine_Table_Exception $e) { foreach ($this->_table->getFilters() as $filter) { - if (($value = $filter->filterSet($this, $name, $value)) !== null) { + if (($value = $filter->filterSet($this, $fieldName, $value)) !== null) { return $value; } } } } } - + + /** + * DESCRIBE WHAT THIS METHOD DOES, PLEASE! + * @todo Refactor. What about composite keys? + */ public function coreSetRelated($name, $value) { $rel = $this->_table->getRelation($name); @@ -929,23 +925,27 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } } else { if ($value !== self::$_null) { + $relatedTable = $value->getTable(); + $foreignFieldName = $relatedTable->getFieldName($rel->getForeign()); + $localFieldName = $this->_table->getFieldName($rel->getLocal()); + // one-to-one relation found if ( ! ($value instanceof Doctrine_Record)) { throw new Doctrine_Record_Exception("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Record or Doctrine_Null when setting one-to-one references."); } if ($rel instanceof Doctrine_Relation_LocalKey) { - $foreign = $rel->getForeign(); - if ( ! empty($foreign) && $foreign != $value->getTable()->getIdentifier()) - $this->set($rel->getLocal(), $value->rawGet($foreign), false); - else - $this->set($rel->getLocal(), $value, false); + if ( ! empty($foreignFieldName) && $foreignFieldName != $value->getTable()->getIdentifier()) { + $this->set($localFieldName, $value->rawGet($foreignFieldName), false); + } else { + $this->set($localFieldName, $value, false); + } } else { - $value->set($rel->getForeign(), $this, false); - } + $value->set($foreignFieldName, $this, false); + } } } - } elseif ($rel instanceof Doctrine_Relation_Association) { + } else if ($rel instanceof Doctrine_Relation_Association) { // join table relation found if ( ! ($value instanceof Doctrine_Collection)) { throw new Doctrine_Record_Exception("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Collection when setting many-to-many references."); @@ -961,21 +961,19 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * @param string $name * @return boolean */ - public function contains($name) + public function contains($fieldName) { - $lower = strtolower($name); - - if (isset($this->_data[$lower])) { + if (isset($this->_data[$fieldName])) { return true; } - if (isset($this->_id[$lower])) { + if (isset($this->_id[$fieldName])) { return true; } - if (isset($this->_values[$lower])) { + if (isset($this->_values[$fieldName])) { return true; } - if (isset($this->_references[$name]) && - $this->_references[$name] !== self::$_null) { + if (isset($this->_references[$fieldName]) && + $this->_references[$fieldName] !== self::$_null) { return true; } @@ -986,10 +984,10 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * @param string $name * @return void */ - public function __unset($name) + public function __unset($fieldName) { - if (isset($this->_data[$name])) { - $this->_data[$name] = array(); + if (isset($this->_data[$fieldName])) { + $this->_data[$fieldName] = array(); } // todo: what to do with references ? } @@ -1054,12 +1052,13 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $conn = $this->_table->getConnection(); } - return $conn->replace($this->_table->getTableName(), $this->getPrepared(), $this->_id); + return $conn->replace($this->_table, $this->getPrepared(), $this->_id); } /** * returns an array of modified fields and associated values * @return array + * @todo What about a better name? getModifiedFields? */ public function getModified() { @@ -1071,6 +1070,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count return $a; } + /** + * REDUNDANT? + */ public function modifiedFields() { $a = array(); @@ -1089,40 +1091,41 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * * @param array $array * @return array + * @todo What about a little bit more expressive name? getPreparedData? */ public function getPrepared(array $array = array()) { $a = array(); if (empty($array)) { - $array = $this->_modified; + $modifiedFields = $this->_modified; } - foreach ($array as $k => $v) { - $type = $this->_table->getTypeOf($v); + foreach ($modifiedFields as $field) { + $type = $this->_table->getTypeOf($field); - if ($this->_data[$v] === self::$_null) { - $a[$v] = null; + if ($this->_data[$field] === self::$_null) { + $a[$field] = null; continue; } switch ($type) { case 'array': case 'object': - $a[$v] = serialize($this->_data[$v]); + $a[$field] = serialize($this->_data[$field]); break; case 'gzip': - $a[$v] = gzcompress($this->_data[$v],5); + $a[$field] = gzcompress($this->_data[$field],5); break; case 'boolean': - $a[$v] = $this->getTable()->getConnection()->convertBooleans($this->_data[$v]); + $a[$field] = $this->getTable()->getConnection()->convertBooleans($this->_data[$field]); break; case 'enum': - $a[$v] = $this->_table->enumIndex($v, $this->_data[$v]); + $a[$field] = $this->_table->enumIndex($field, $this->_data[$field]); break; default: - if ($this->_data[$v] instanceof Doctrine_Record) { - $this->_data[$v] = $this->_data[$v]->getIncremented(); + if ($this->_data[$field] instanceof Doctrine_Record) { + $this->_data[$field] = $this->_data[$field]->getIncremented(); } /** TODO: if ($this->_data[$v] === null) { @@ -1130,7 +1133,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } */ - $a[$v] = $this->_data[$v]; + $a[$field] = $this->_data[$field]; } } $map = $this->_table->inheritanceMap; @@ -1255,12 +1258,12 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count * @param mixed $name name of the property or reference * @return boolean */ - public function hasRelation($name) + public function hasRelation($fieldName) { - if (isset($this->_data[$name]) || isset($this->_id[$name])) { + if (isset($this->_data[$fieldName]) || isset($this->_id[$fieldName])) { return true; } - return $this->_table->hasRelation($name); + return $this->_table->hasRelation($fieldName); } /** @@ -1311,8 +1314,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count if ( ! ($val instanceof Doctrine_Null)) { $ret->_modified[] = $key; } - } - + } return $ret; } @@ -1356,7 +1358,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $this->_state = Doctrine_Record::STATE_CLEAN; $this->_modified = array(); } else { - $name = $this->_table->getIdentifier(); + $name = $this->_table->getIdentifier(); $this->_id[$name] = $id; $this->_data[$name] = $id; $this->_state = Doctrine_Record::STATE_CLEAN; @@ -1481,12 +1483,12 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count */ public function merge(array $values) { - foreach ($this->_table->getColumnNames() as $value) { + foreach ($this->_table->getFieldNames() as $fieldName) { try { - if (isset($values[$value])) { - $this->set($value, $values[$value]); + if (isset($values[$fieldName])) { + $this->set($fieldName, $values[$fieldName]); } - } catch(Doctrine_Exception $e) { + } catch (Doctrine_Exception $e) { // silence all exceptions } } @@ -1506,12 +1508,12 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count array_shift($args); if (isset($args[0])) { - $column = $args[0]; - $args[0] = $this->get($column); + $fieldName = $args[0]; + $args[0] = $this->get($fieldName); $newvalue = call_user_func_array($callback, $args); - $this->_data[$column] = $newvalue; + $this->_data[$fieldName] = $newvalue; } return $this; } @@ -1592,8 +1594,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $q->execute(); - - } elseif ($rel instanceof Doctrine_Relation_ForeignKey) { + } else if ($rel instanceof Doctrine_Relation_ForeignKey) { $q->update($rel->getTable()->getComponentName()) ->set($rel->getForeign(), '?', array(null)) ->addWhere($rel->getForeign() . ' = ?', array_values($this->identifier())); diff --git a/lib/Doctrine/Relation/Parser.php b/lib/Doctrine/Relation/Parser.php index f2b309047..0ecc32c70 100644 --- a/lib/Doctrine/Relation/Parser.php +++ b/lib/Doctrine/Relation/Parser.php @@ -29,6 +29,7 @@ * @version $Revision: 1397 $ * @link www.phpdoctrine.com * @since 1.0 + * @todo Composite key support? */ class Doctrine_Relation_Parser { @@ -103,11 +104,12 @@ class Doctrine_Relation_Parser unset($this->relations[$name]); } + /* looks like old code? $lower = strtolower($name); - if ($this->_table->hasColumn($lower)) { throw new Doctrine_Relation_Exception("Couldn't bind relation. Column with name " . $lower . ' already exists!'); } + */ $e = explode(' as ', $name); $name = $e[0]; @@ -145,6 +147,8 @@ class Doctrine_Relation_Parser if (isset($this->_pending[$alias])) { $def = $this->_pending[$alias]; + $identifierColumnNames = $this->_table->getIdentifierColumnNames(); + $idColumnName = array_pop($identifierColumnNames); // check if reference class name exists // if it does we are dealing with association relation @@ -160,7 +164,7 @@ class Doctrine_Relation_Parser $parser->bind($this->_table->getComponentName(), array('type' => Doctrine_Relation::ONE, 'local' => $def['local'], - 'foreign' => $this->_table->getIdentifier(), + 'foreign' => $idColumnName, 'localKey' => true, )); } @@ -168,7 +172,7 @@ class Doctrine_Relation_Parser if ( ! $this->hasRelation($def['refClass'])) { $this->bind($def['refClass'], array('type' => Doctrine_Relation::MANY, 'foreign' => $def['local'], - 'local' => $this->_table->getIdentifier())); + 'local' => $idColumnName)); } } if (in_array($def['class'], $localClasses)) { @@ -181,7 +185,6 @@ class Doctrine_Relation_Parser $def = $this->completeDefinition($def); if (isset($def['localKey'])) { - $rel = new Doctrine_Relation_LocalKey($def); } else { $rel = new Doctrine_Relation_ForeignKey($def); @@ -257,7 +260,7 @@ class Doctrine_Relation_Parser $def['class'] = $def['table']->getComponentName(); $def['refTable'] = $this->getImpl($def['refClass']); - $id = $def['refTable']->getIdentifier(); + $id = $def['refTable']->getIdentifierColumnNames(); if (count($id) > 1) { if ( ! isset($def['foreign'])) { @@ -304,15 +307,15 @@ class Doctrine_Relation_Parser */ public function getIdentifiers(Doctrine_Table $table) { + $componentNameToLower = strtolower($table->getComponentName()); if (is_array($table->getIdentifier())) { - $columns = array(); - foreach((array) $table->getIdentifier() as $identifier) { - $columns[] = strtolower($table->getComponentName()) - . '_' . $table->getIdentifier(); + $columns = array(); + foreach ((array) $table->getIdentifierColumnNames() as $identColName) { + $columns[] = $componentNameToLower . '_' . $identColName; } } else { - $columns = strtolower($table->getComponentName()) - . '_' . $table->getIdentifier(); + $columns = $componentNameToLower . '_' . $table->getColumnName( + $table->getIdentifier()); } return $columns; @@ -361,6 +364,8 @@ class Doctrine_Relation_Parser * * @param array $def definition array to be completed * @return array completed definition array + * @todo Description: What does it mean to complete a definition? What is done (not how)? + * Refactor (too long & nesting level) */ public function completeDefinition($def) { @@ -371,21 +376,26 @@ class Doctrine_Relation_Parser $foreignClasses = array_merge($def['table']->getOption('parents'), array($def['class'])); $localClasses = array_merge($this->_table->getOption('parents'), array($this->_table->getComponentName())); + $localIdentifierColumnNames = $this->_table->getIdentifierColumnNames(); + $localIdColumnName = array_pop($localIdentifierColumnNames); + $foreignIdentifierColumnNames = $def['table']->getIdentifierColumnNames(); + $foreignIdColumnName = array_pop($foreignIdentifierColumnNames); + if (isset($def['local'])) { if ( ! isset($def['foreign'])) { // local key is set, but foreign key is not // try to guess the foreign key - if ($def['local'] === $this->_table->getIdentifier()) { + if ($def['local'] === $localIdColumnName) { $def['foreign'] = $this->guessColumns($localClasses, $def['table']); } else { // the foreign field is likely to be the // identifier of the foreign class - $def['foreign'] = $def['table']->getIdentifier(); + $def['foreign'] = $foreignIdColumnName; $def['localKey'] = true; } } else { - if ($def['local'] !== $this->_table->getIdentifier() && + if ($def['local'] !== $localIdColumnName && $def['type'] == Doctrine_Relation::ONE) { $def['localKey'] = true; } @@ -394,15 +404,15 @@ class Doctrine_Relation_Parser if (isset($def['foreign'])) { // local key not set, but foreign key is set // try to guess the local key - if ($def['foreign'] === $def['table']->getIdentifier()) { + if ($def['foreign'] === $foreignIdColumnName) { $def['localKey'] = true; try { $def['local'] = $this->guessColumns($foreignClasses, $this->_table); } catch (Doctrine_Relation_Exception $e) { - $def['local'] = $this->_table->getIdentifier(); + $def['local'] = $localIdColumnName; } } else { - $def['local'] = $this->_table->getIdentifier(); + $def['local'] = $localIdColumnName; } } else { // neither local or foreign key is being set @@ -412,16 +422,17 @@ class Doctrine_Relation_Parser // the following loops are needed for covering inheritance foreach ($localClasses as $class) { - $table = $conn->getTable($class); + $table = $conn->getTable($class); + $identifierColumnNames = $table->getIdentifierColumnNames(); + $idColumnName = array_pop($identifierColumnNames); $column = strtolower($table->getComponentName()) - . '_' . $table->getIdentifier(); + . '_' . $idColumnName; foreach ($foreignClasses as $class2) { $table2 = $conn->getTable($class2); if ($table2->hasColumn($column)) { $def['foreign'] = $column; - $def['local'] = $table->getIdentifier(); - + $def['local'] = $idColumnName; return $def; } } @@ -429,13 +440,15 @@ class Doctrine_Relation_Parser foreach ($foreignClasses as $class) { $table = $conn->getTable($class); + $identifierColumnNames = $table->getIdentifierColumnNames(); + $idColumnName = array_pop($identifierColumnNames); $column = strtolower($table->getComponentName()) - . '_' . $table->getIdentifier(); + . '_' . $idColumnName; foreach ($localClasses as $class2) { $table2 = $conn->getTable($class2); if ($table2->hasColumn($column)) { - $def['foreign'] = $table->getIdentifier(); + $def['foreign'] = $idColumnName; $def['local'] = $column; $def['localKey'] = true; return $def; @@ -445,11 +458,12 @@ class Doctrine_Relation_Parser // auto-add columns and auto-build relation $columns = array(); - foreach ((array) $this->_table->getIdentifier() as $id) { + foreach ((array) $this->_table->getIdentifierColumnNames() as $id) { + // ?? should this not be $this->_table->getComponentName() ?? $column = strtolower($table->getComponentName()) . '_' . $id; - $col = $this->_table->getDefinitionOf($id); + $col = $this->_table->getColumnDefinition($id); $type = $col['type']; $length = $col['length']; @@ -468,7 +482,7 @@ class Doctrine_Relation_Parser } else { $def['foreign'] = $columns[0]; } - $def['local'] = $this->_table->getIdentifier(); + $def['local'] = $localIdColumnName; } } return $def; diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index 958196086..94028a2db 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -40,9 +40,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable protected $_data = array(); /** - * @var mixed $identifier + * @var mixed $identifier The field names of all fields that are part of the identifier/primary key */ - protected $_identifier; + protected $_identifier = array(); /** * @see Doctrine_Identifier constants @@ -67,7 +67,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable /** * @var array $columns an array of column definitions, - * keys as column names and values as column definitions + * keys are column names and values are column definitions * * the definition array has atleast the following values: * @@ -83,10 +83,20 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable protected $_columns = array(); /** - * @var array $columnAliases an array of column aliases - * keys as column aliases and values as column names + * @var array $_fieldNames an array of field names. used to look up field names + * from column names. + * keys are column names and values are field names */ - protected $_columnAliases = array(); + protected $_fieldNames = array(); + + /** + * + * @var array $_columnNames an array of column names + * keys are field names and values column names. + * used to look up column names from field names. + * this is the reverse lookup map of $_fieldNames. + */ + protected $_columnNames = array(); /** * @var integer $columnCount cached column count, Doctrine_Record uses this column count in when @@ -202,7 +212,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $this->_parser = new Doctrine_Relation_Parser($this); if ($initDefinition) { - $record = $this->initDefinition($name); + $record = $this->initDefinition(); $this->initIdentifier(); @@ -216,8 +226,15 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $this->_filters[] = new Doctrine_Record_Filter_Standard(); $this->_repository = new Doctrine_Table_Repository($this); } - public function initDefinition($name) - { + + /** + * Initializes the in-memory table definition. + * + * @param string $name + */ + public function initDefinition() + { + $name = $this->_options['name']; if ( ! class_exists($name) || empty($name)) { throw new Doctrine_Exception("Couldn't find class " . $name); } @@ -253,15 +270,16 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $record->setTableDefinition(); // get the declaring class of setTableDefinition method $method = new ReflectionMethod($this->_options['name'], 'setTableDefinition'); - $class = $method->getDeclaringClass(); + $class = $method->getDeclaringClass(); + } else { $class = new ReflectionClass($class); } - $this->_options['joinedParents'] = array(); foreach (array_reverse($this->_options['parents']) as $parent) { + if ($parent === $class->getName()) { continue; } @@ -270,25 +288,25 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable if ($ref->isAbstract()) { continue; } - $table = $this->_conn->getTable($parent); + $parentTable = $this->_conn->getTable($parent); $found = false; - $columns = $table->getColumns(); + $parentColumns = $parentTable->getColumns(); - foreach ($columns as $column => $definition) { + foreach ($parentColumns as $columnName => $definition) { if ( ! isset($definition['primary'])) { - if (isset($this->_columns[$column])) { + if (isset($this->_columns[$columnName])) { $found = true; break; } else { - if ( ! isset($columns[$column]['owner'])) { - $columns[$column]['owner'] = $table->getComponentName(); + if ( ! isset($parentColumns[$columnName]['owner'])) { + $parentColumns[$columnName]['owner'] = $parentTable->getComponentName(); } - $this->_options['joinedParents'][] = $columns[$column]['owner']; + $this->_options['joinedParents'][] = $parentColumns[$columnName]['owner']; } } else { - unset($columns[$column]); + unset($parentColumns[$columnName]); } } @@ -296,7 +314,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable continue; } - $this->_columns = array_merge($columns, $this->_columns); + foreach ($parentColumns as $columnName => $definition) { + $fullName = $columnName . ' as ' . $parentTable->getFieldName($columnName); + $this->setColumn($fullName, $definition['type'], $definition['length'], $definition, true); + } break; } @@ -318,6 +339,11 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable return $record; } + + /** + * Initializes the table identifier(s)/primary key(s) + * + */ public function initIdentifier() { switch (count($this->_identifier)) { @@ -342,15 +368,16 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable unset($definition['sequence']); // add the inherited primary key column - $this->_columns = array_merge(array($id => $definition), $this->_columns); + $fullName = $id . ' as ' . $table->getFieldName($id); + $this->setColumn($fullName, $definition['type'], $definition['length'], + $definition, true); } - } else { - $this->_columns = array_merge(array('id' => - array('type' => 'integer', - 'length' => 20, - 'autoincrement' => true, - 'primary' => true)), $this->_columns); + $definition = array('type' => 'integer', + 'length' => 20, + 'autoincrement' => true, + 'primary' => true); + $this->setColumn('id', $definition['type'], $definition['length'], $definition, true); $this->_identifier = 'id'; $this->_identifierType = Doctrine::IDENTIFIER_AUTOINC; } @@ -358,7 +385,8 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable break; case 1: foreach ($this->_identifier as $pk) { - $e = $this->_columns[$pk]; + $columnName = $this->getColumnName($pk); + $e = $this->_columns[$columnName]; $found = false; @@ -404,25 +432,46 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $this->_identifierType = Doctrine::IDENTIFIER_COMPOSITE; } } - - public function getColumnOwner($column) + + /** + * Gets the owner of a column. + * The owner of a column is the name of the component in a hierarchy that + * defines the column. + * + * @param string $columnName The column name + * @return string The name of the owning/defining component + */ + public function getColumnOwner($columnName) { - if (isset($this->_columns[$column]['owner'])) { - return $this->_columns[$column]['owner']; + if (isset($this->_columns[$columnName]['owner'])) { + return $this->_columns[$columnName]['owner']; } else { return $this->getComponentName(); } } - - public function isInheritedColumn($column) + + /** + * Checks whether a column is inherited from a component further up in the hierarchy. + * + * @param $columnName The column name + * @return boolean TRUE if column is inherited, FALSE otherwise. + */ + public function isInheritedColumn($columnName) { - return (isset($this->_columns[$column]['owner'])); + return (isset($this->_columns[$columnName]['owner'])); } - - public function isIdentifier($identifier) + + /** + * Checks whether a field is part of the table identifier/primary key field(s). + * + * @param string $fieldName The field name + * @return boolean TRUE if the field is part of the table identifier/primary key field(s), + * FALSE otherwise. + */ + public function isIdentifier($fieldName) { - return ($identifier === $this->_identifier || - in_array($identifier, (array) $this->_identifier)); + return ($fieldName === $this->getIdentifier() || + in_array($fieldName, (array) $this->getIdentifier())); } public function getMethodOwner($method) @@ -472,10 +521,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $columns = array(); $primary = array(); - foreach ($this->getColumns() as $name => $column) { - $definition = $column; + foreach ($this->getColumns() as $name => $definition) { - if (isset($column['owner'])) { + if (isset($definition['owner'])) { continue; } @@ -499,52 +547,50 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } $options['foreignKeys'] = array(); - if ($parseForeignKeys) { - if ($this->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_CONSTRAINTS) { - $constraints = array(); + if ($parseForeignKeys && $this->getAttribute(Doctrine::ATTR_EXPORT) + & Doctrine::EXPORT_CONSTRAINTS) { - $emptyIntegrity = array('onUpdate' => null, - 'onDelete' => null); + $constraints = array(); - foreach ($this->getRelations() as $name => $relation) { - $fk = $relation->toArray(); - $fk['foreignTable'] = $relation->getTable()->getTableName(); + $emptyIntegrity = array('onUpdate' => null, + 'onDelete' => null); - if ($relation->getTable() === $this && in_array($relation->getLocal(), $primary)) { - if ($relation->hasConstraint()) { - throw new Doctrine_Table_Exception("Badly constructed integrity constraints."); - } + foreach ($this->getRelations() as $name => $relation) { + $fk = $relation->toArray(); + $fk['foreignTable'] = $relation->getTable()->getTableName(); - continue; + if ($relation->getTable() === $this && in_array($relation->getLocal(), $primary)) { + if ($relation->hasConstraint()) { + throw new Doctrine_Table_Exception("Badly constructed integrity constraints."); } + continue; + } - $integrity = array('onUpdate' => $fk['onUpdate'], - 'onDelete' => $fk['onDelete']); + $integrity = array('onUpdate' => $fk['onUpdate'], + 'onDelete' => $fk['onDelete']); - if ($relation instanceof Doctrine_Relation_LocalKey) { - $def = array('local' => $relation->getLocal(), - 'foreign' => $relation->getForeign(), - 'foreignTable' => $relation->getTable()->getTableName()); + if ($relation instanceof Doctrine_Relation_LocalKey) { + $def = array('local' => $relation->getLocal(), + 'foreign' => $relation->getForeign(), + 'foreignTable' => $relation->getTable()->getTableName()); - if (($key = array_search($def, $options['foreignKeys'])) === false) { - $options['foreignKeys'][] = $def; - - $constraints[] = $integrity; - } else { - if ($integrity !== $emptyIntegrity) { - $constraints[$key] = $integrity; - } + if (($key = array_search($def, $options['foreignKeys'])) === false) { + $options['foreignKeys'][] = $def; + $constraints[] = $integrity; + } else { + if ($integrity !== $emptyIntegrity) { + $constraints[$key] = $integrity; } } } + } - foreach ($constraints as $k => $def) { - $options['foreignKeys'][$k] = array_merge($options['foreignKeys'][$k], $def); - } - + foreach ($constraints as $k => $def) { + $options['foreignKeys'][$k] = array_merge($options['foreignKeys'][$k], $def); } } + $options['primary'] = $primary; return array('tableName' => $this->getOption('tableName'), @@ -568,9 +614,8 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $this->_conn->export->createIndex($this->_options['tableName'], $index, $definition); } $this->_conn->commit(); - } catch(Doctrine_Connection_Exception $e) { + } catch (Doctrine_Connection_Exception $e) { $this->_conn->rollback(); - throw $e; } } @@ -676,6 +721,12 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable return false; } + + /** + * DESCRIBE WHAT THIS METHOD DOES, PLEASE! + * + * @todo Name proposal: addRelation + */ public function bind($args, $type) { $options = array(); @@ -833,14 +884,41 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param string $alias column alias * @return string column name */ - public function getColumnName($alias) + public function getColumnName($fieldName) { - $alias = strtolower($alias); - if (isset($this->_columnAliases[$alias])) { - return $this->_columnAliases[$alias]; + if (isset($this->_columnNames[$fieldName])) { + return $this->_columnNames[$fieldName]; } - - return $alias; + return $fieldName; + } + + /** + * + * + */ + public function getColumnDefinition($columnName) + { + if ( ! isset($this->_columns[$columnName])) { + return false; + } + return $this->_columns[$columnName]; + } + + /** + * getColumnAlias + * + * returns a column alias for a column name + * if no alias can be found the column name is returned. + * + * @param string $columnName column name + * @return string column alias + */ + public function getFieldName($columnName) + { + if (isset($this->_fieldNames[$columnName])) { + return $this->_fieldNames[$columnName]; + } + return $columnName; } /** @@ -850,10 +928,12 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param string $type * @param integer $length * @param mixed $options + * @param boolean $prepend Whether to prepend or append the new column to the column list. + * By default the column gets appended. * @throws Doctrine_Table_Exception if trying use wrongly typed parameter * @return void */ - public function setColumn($name, $type, $length = null, $options = array()) + public function setColumn($name, $type, $length = null, $options = array(), $prepend = false) { if (is_string($options)) { $options = explode('|', $options); @@ -867,16 +947,17 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable unset($options[$k]); } } - - $name = strtolower($name); + + // extract column name & field name $parts = explode(' as ', $name); - if (count($parts) > 1) { - $this->_columnAliases[$parts[1]] = $parts[0]; - $name = $parts[0]; + $fieldName = $parts[1]; + } else { + $fieldName = $parts[0]; } - - + $name = strtolower($parts[0]); + $this->_columnNames[$fieldName] = $name; + $this->_fieldNames[$name] = $fieldName; if ($length == null) { switch ($type) { @@ -905,13 +986,23 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable break; } } - - $this->_columns[$name] = $options; - $this->_columns[$name]['type'] = $type; - $this->_columns[$name]['length'] = $length; + + $options['type'] = $type; + $options['length'] = $length; + + if ($prepend) { + $this->_columns = array_merge(array($name => $options), $this->_columns); + } else { + $this->_columns[$name] = $options; + } if (isset($options['primary'])) { - $this->_identifier[] = $name; + if (isset($this->_identifier)) { + $this->_identifier = (array) $this->_identifier; + } + if ( ! in_array($fieldName, $this->_identifier)) { + $this->_identifier[] = $fieldName; + } } if (isset($options['default'])) { $this->hasDefaultValues = true; @@ -933,17 +1024,17 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * getDefaultValueOf * returns the default value(if any) for given column * - * @param string $column + * @param string $fieldName * @return mixed */ - public function getDefaultValueOf($column) + public function getDefaultValueOf($fieldName) { - $column = strtolower($column); - if ( ! isset($this->_columns[$column])) { - throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$column." doesn't exist."); + $columnName = $this->getColumnName($fieldName); + if ( ! isset($this->_columns[$columnName])) { + throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$columnName." doesn't exist."); } - if (isset($this->_columns[$column]['default'])) { - return $this->_columns[$column]['default']; + if (isset($this->_columns[$columnName]['default'])) { + return $this->_columns[$columnName]['default']; } else { return null; } @@ -969,9 +1060,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * hasColumn * @return boolean */ - public function hasColumn($name) + public function hasColumn($columnName) { - return isset($this->_columns[$name]); + return isset($this->_columns[$columnName]); } /** @@ -1030,7 +1121,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $id = is_array($id) ? array_values($id) : array($id); return $this->createQuery() - ->where(implode(' = ? AND ', (array) $this->_identifier) . ' = ?') + ->where(implode(' = ? AND ', $this->getIdentifierColumnNames()) . ' = ?') ->fetchOne($id, $hydrationMode); } @@ -1111,6 +1202,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * clears the first level cache (identityMap) * * @return void + * @todo what about a more descriptive name? clearIdentityMap? */ public function clear() { @@ -1167,29 +1259,27 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable public function getRecord() { if ( ! empty($this->_data)) { - $this->_data = array_change_key_case($this->_data, CASE_LOWER); - $key = $this->getIdentifier(); + $identifierFieldNames = $this->getIdentifier(); - if ( ! is_array($key)) { - $key = array($key); + if ( ! is_array($identifierFieldNames)) { + $identifierFieldNames = array($identifierFieldNames); } $found = false; - foreach ($key as $k) { - if ( ! isset($this->_data[$k])) { + foreach ($identifierFieldNames as $fieldName) { + if ( ! isset($this->_data[$fieldName])) { // primary key column not found return new record $found = true; break; } - $id[] = $this->_data[$k]; + $id[] = $this->_data[$fieldName]; } if ($found) { $recordName = $this->getClassnameToReturn(); $record = new $recordName($this, true); $this->_data = array(); - return $record; } @@ -1210,7 +1300,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $record = new $recordName($this, true); } - return $record; } @@ -1257,9 +1346,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable final public function getProxy($id = null) { if ($id !== null) { - $query = 'SELECT ' . implode(', ', (array) $this->_identifier) + $identifierColumnNames = $this->getIdentifierColumnNames(); + $query = 'SELECT ' . implode(', ', (array) $identifierColumnNames) . ' FROM ' . $this->getTableName() - . ' WHERE ' . implode(' = ? && ', (array) $this->_identifier) . ' = ?'; + . ' WHERE ' . implode(' = ? && ', (array) $identifierColumnNames) . ' = ?'; $query = $this->applyInheritance($query); $params = array_merge(array($id), array_values($this->_options['inheritanceMap'])); @@ -1282,7 +1372,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable if ( ! empty($this->_options['inheritanceMap'])) { $a = array(); foreach ($this->_options['inheritanceMap'] as $field => $value) { - $a[] = $field . ' = ?'; + $a[] = $this->getColumnName($field) . ' = ?'; } $i = implode(' AND ', $a); $where .= ' AND ' . $i; @@ -1302,7 +1392,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } /** - * @return Doctrine_Query a Doctrine_Query object + * @return Doctrine_Query a Doctrine_Query object */ public function getQueryObject() { @@ -1312,13 +1402,14 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } /** - * @param string $field + * @param string $fieldName * @return array */ - public function getEnumValues($field) + public function getEnumValues($fieldName) { - if (isset($this->_columns[$field]['values'])) { - return $this->_columns[$field]['values']; + $columnName = $this->getColumnName($fieldName); + if (isset($this->_columns[$columnName]['values'])) { + return $this->_columns[$columnName]['values']; } else { return array(); } @@ -1331,16 +1422,17 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param integer $index * @return mixed */ - public function enumValue($field, $index) + public function enumValue($fieldName, $index) { if ($index instanceof Doctrine_Null) { return $index; } - + + $columnName = $this->getColumnName($fieldName); if ( ! $this->_conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM) - && isset($this->_columns[$field]['values'][$index]) + && isset($this->_columns[$columnName]['values'][$index]) ) { - return $this->_columns[$field]['values'][$index]; + return $this->_columns[$columnName]['values'][$index]; } return $index; @@ -1353,9 +1445,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param mixed $value * @return mixed */ - public function enumIndex($field, $value) + public function enumIndex($fieldName, $value) { - $values = $this->getEnumValues($field); + $values = $this->getEnumValues($fieldName); $index = array_search($value, $values); if ($index === false || !$this->_conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) { @@ -1363,7 +1455,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } return $value; } - /* getColumnCount + + /** + * getColumnCount * * @return integer the number of columns in this table */ @@ -1388,11 +1482,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * * @return boolean */ - public function removeColumn($column) + public function removeColumn($columnName) { - if (isset($this->_columns[$column])) { - unset($this->_columns[$column]); - + if (isset($this->_columns[$columnName])) { + unset($this->_columns[$columnName]); return true; } @@ -1400,13 +1493,41 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } /** - * returns an array containing all the column names + * returns an array containing all the column names. * * @return array */ - public function getColumnNames() + public function getColumnNames(array $fieldNames = null) { - return array_keys($this->_columns); + if ($fieldNames === null) { + return array_keys($this->_columns); + } else { + $columnNames = array(); + foreach ($fieldNames as $fieldName) { + $columnNames[] = $this->getColumnName($fieldName); + } + return $columnNames; + } + } + + /** + * returns an array with all the identifier column names. + * + * @return array + */ + public function getIdentifierColumnNames() + { + return $this->getColumnNames((array) $this->getIdentifier()); + } + + /** + * returns an array containing all the field names. + * + * @return array + */ + public function getFieldNames() + { + return array_values($this->_fieldNames); } /** @@ -1414,12 +1535,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * * @return mixed array on success, false on failure */ - public function getDefinitionOf($column) + public function getDefinitionOf($fieldName) { - if (isset($this->_columns[$column])) { - return $this->_columns[$column]; - } - return false; + $columnName = $this->getColumnName($fieldName); + return $this->getColumnDefinition($columnName); } /** @@ -1427,10 +1546,11 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * * @return mixed string on success, false on failure */ - public function getTypeOf($column) + public function getTypeOf($fieldName) { - if (isset($this->_columns[$column])) { - return $this->_columns[$column]['type']; + $columnName = $this->getColumnName($fieldName); + if (isset($this->_columns[$columnName])) { + return $this->_columns[$columnName]['type']; } return false; } @@ -1482,14 +1602,14 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param string $value field value * @return mixed prepared value */ - public function prepareValue($field, $value) + public function prepareValue($fieldName, $value) { if ($value === self::$_null) { return self::$_null; } elseif ($value === null) { return null; } else { - $type = $this->getTypeOf($field); + $type = $this->getTypeOf($fieldName); switch ($type) { case 'array': @@ -1498,7 +1618,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $value = unserialize($value); if ($value === false) { - throw new Doctrine_Table_Exception('Unserialization of ' . $field . ' failed.'); + throw new Doctrine_Table_Exception('Unserialization of ' . $fieldName . ' failed.'); } return $value; } @@ -1507,12 +1627,12 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $value = gzuncompress($value); if ($value === false) { - throw new Doctrine_Table_Exception('Uncompressing of ' . $field . ' failed.'); + throw new Doctrine_Table_Exception('Uncompressing of ' . $fieldName . ' failed.'); } return $value; break; case 'enum': - return $this->enumValue($field, $value); + return $this->enumValue($fieldName, $value); break; case 'boolean': return (boolean) $value; @@ -1706,9 +1826,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param string $hydrationMode * @return void */ - protected function findBy($column, $value, $hydrationMode = null) + protected function findBy($fieldName, $value, $hydrationMode = null) { - return $this->createQuery()->where($column . ' = ?')->execute(array($value), $hydrationMode); + return $this->createQuery()->where($fieldName . ' = ?')->execute(array($value), $hydrationMode); } /** @@ -1719,11 +1839,11 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable * @param string $hydrationMode * @return void */ - protected function findOneBy($column, $value, $hydrationMode = null) + protected function findOneBy($fieldName, $value, $hydrationMode = null) { - $results = $this->createQuery()->where($column . ' = ?')->limit(1)->execute(array($value), $hydrationMode); + $results = $this->createQuery()->where($fieldName . ' = ?')->limit(1)->execute(array($value), $hydrationMode); - return $hydrationMode === Doctrine::FETCH_ARRAY ? $results[0]:$results->getFirst(); + return $hydrationMode === Doctrine::FETCH_ARRAY ? $results[0] : $results->getFirst(); } /** @@ -1746,15 +1866,15 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } if (isset($by)) { - if (!isset($arguments[0])) { + if ( ! isset($arguments[0])) { throw new Doctrine_Table_Exception('You must specify the value to findBy'); } - $column = Doctrine::tableize($by); + $fieldName = Doctrine::tableize($by); $hydrationMode = isset($arguments[1]) ? $arguments[1]:null; - if ($this->hasColumn($column)) { - return $this->$method($column, $arguments[0], $hydrationMode); + if ($this->hasColumn($fieldName)) { + return $this->$method($fieldName, $arguments[0], $hydrationMode); } else if ($this->hasRelation($by)) { $relation = $this->getRelation($by); diff --git a/lib/Doctrine/Transaction.php b/lib/Doctrine/Transaction.php index 93eb8715e..e3263516a 100644 --- a/lib/Doctrine/Transaction.php +++ b/lib/Doctrine/Transaction.php @@ -56,6 +56,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module /** * @var array $invalid an array containing all invalid records within this transaction + * @todo What about a more verbose name? $invalidRecords? */ protected $invalid = array(); @@ -294,12 +295,19 @@ class Doctrine_Transaction extends Doctrine_Connection_Module * @param string $savepoint name of a savepoint to rollback to * @throws Doctrine_Transaction_Exception if the rollback operation fails at database level * @return boolean false if rollback couldn't be performed, true otherwise + * @todo Shouldnt this method only commit a rollback if the transactionLevel is 1 + * (STATE_ACTIVE)? Explanation: Otherwise a rollback that is triggered from inside doctrine + * in an (emulated) nested transaction would lead to a complete database level + * rollback even though the client code did not yet want to do that. + * In other words: if the user starts a transaction doctrine shouldnt roll it back. + * Doctrine should only roll back transactions started by doctrine. Thoughts? */ public function rollback($savepoint = null) { $this->conn->connect(); - - if ($this->transactionLevel == 0) { + $currentState = $this->getState(); + + if ($currentState != self::STATE_ACTIVE && $currentState != self::STATE_BUSY) { return false; } diff --git a/models/ColumnAliasTest.php b/models/ColumnAliasTest.php index 633eaede1..5f8e96713 100644 --- a/models/ColumnAliasTest.php +++ b/models/ColumnAliasTest.php @@ -4,9 +4,12 @@ class ColumnAliasTest extends Doctrine_Record public function setTableDefinition() { $this->hasColumn('column1 as alias1', 'string', 200); - $this->hasColumn('column2 as alias2', 'integer', 11); + $this->hasColumn('column2 as alias2', 'integer', 4); + $this->hasColumn('another_column as anotherField', 'string', 50); + $this->hasColumn('book_id as bookId', 'integer', 4); } - public function setUp() + public function setUp() { + $this->hasOne('Book as book', array('local' => 'book_id', 'foreign' => 'id')); } } diff --git a/tests/AccessTestCase.php b/tests/AccessTestCase.php index c3722568a..a0ff652ef 100644 --- a/tests/AccessTestCase.php +++ b/tests/AccessTestCase.php @@ -48,7 +48,7 @@ class Doctrine_Access_TestCase extends Doctrine_UnitTestCase public function testIsset() { $user = new User(); - + $this->assertTrue(isset($user->name)); $this->assertFalse(isset($user->unknown)); @@ -70,7 +70,7 @@ class Doctrine_Access_TestCase extends Doctrine_UnitTestCase public function testOffsetMethods() { $user = new User(); - $this->assertEqual($user['name'],null); + $this->assertEqual($user['name'], null); $user['name'] = 'Jack'; $this->assertEqual($user['name'], 'Jack'); diff --git a/tests/ClassTableInheritanceTestCase.php b/tests/ClassTableInheritanceTestCase.php index 53628b5a6..9e687eba4 100644 --- a/tests/ClassTableInheritanceTestCase.php +++ b/tests/ClassTableInheritanceTestCase.php @@ -109,7 +109,7 @@ class Doctrine_ClassTableInheritance_TestCase extends Doctrine_UnitTestCase $q = new Doctrine_Query(); $q->from('CTITest c')->where('c.id = 1'); - $this->assertEqual($q->getSql(), 'SELECT c.id AS c__id, c2.name AS c__name, c2.verified AS c__verified, c3.added AS c__added, c.age AS c__age FROM c_t_i_test_parent4 c LEFT JOIN c_t_i_test_parent2 c2 ON c.id = c2.id LEFT JOIN c_t_i_test_parent3 c3 ON c.id = c3.id WHERE c.id = 1'); + $this->assertEqual($q->getSql(), 'SELECT c.id AS c__id, c3.added AS c__added, c2.name AS c__name, c2.verified AS c__verified, c.age AS c__age FROM c_t_i_test_parent4 c LEFT JOIN c_t_i_test_parent2 c2 ON c.id = c2.id LEFT JOIN c_t_i_test_parent3 c3 ON c.id = c3.id WHERE c.id = 1'); $record = $q->fetchOne(); diff --git a/tests/ColumnAliasTestCase.php b/tests/ColumnAliasTestCase.php index 537fb50b7..4ccac79aa 100644 --- a/tests/ColumnAliasTestCase.php +++ b/tests/ColumnAliasTestCase.php @@ -33,14 +33,60 @@ class Doctrine_ColumnAlias_TestCase extends Doctrine_UnitTestCase { public function prepareData() - { } + { + $book1 = new Book(); + $book1->name = 'Das Boot'; + $book1->save(); + + $record1 = new ColumnAliasTest(); + $record1->alias1 = 'first'; + $record1->alias2 = 123; + $record1->anotherField = 'camelCase'; + $record1->bookId = $book1->id; + $record1->save(); + + $record2 = new ColumnAliasTest(); + $record2->alias1 = 'one'; + $record2->alias2 = 456; + $record2->anotherField = 'KoQ'; + $record2->save(); + + $record2->anotherField = 'foo'; + } + public function prepareTables() { - $this->tables = array('ColumnAliasTest'); + $this->tables = array('ColumnAliasTest', 'Book'); parent::prepareTables(); } + public function testAliasesAreSupportedForJoins() + { + $q = new Doctrine_Query(); + $q->select('c.*, b.name')->from('ColumnAliasTest c') + ->innerJoin('c.book b') + ->where('c.anotherField = ?', 'camelCase'); + $result = $q->execute(); + $this->assertTrue(isset($result[0]->book)); + $this->assertEqual($result[0]->book->name, 'Das Boot'); + } + + public function testAliasesAreSupportedForArrayFetching() + { + $q = new Doctrine_Query(); + $q->select('c.*, b.name')->from('ColumnAliasTest c') + ->innerJoin('c.book b') + ->where('c.anotherField = ?', 'camelCase') + ->setHydrationMode(Doctrine::HYDRATE_ARRAY); + $result = $q->execute(); + $this->assertEqual($result[0]['alias1'], 'first'); + $this->assertEqual($result[0]['alias2'], 123); + $this->assertEqual($result[0]['anotherField'], 'camelCase'); + $this->assertTrue(isset($result[0]['book'])); + $this->assertEqual($result[0]['book']['name'], 'Das Boot'); + } + public function testAliasesAreSupportedForRecordPropertyAccessors() { $record = new ColumnAliasTest; @@ -50,58 +96,60 @@ class Doctrine_ColumnAlias_TestCase extends Doctrine_UnitTestCase $this->assertEqual($record->alias1, 'someone'); $this->assertEqual($record->alias2, 187); - } catch(Doctrine_Record_Exception $e) { + } catch (Doctrine_Record_Exception $e) { $this->fail(); } - $record->save(); } + public function testAliasesAreSupportedForDqlSelectPart() { $q = new Doctrine_Query(); - - $q->select('c.alias1, c.alias2')->from('ColumnAliasTest c'); - + $q->select('c.alias1, c.alias2, c.anotherField')->from('ColumnAliasTest c'); $coll = $q->execute(); - $this->assertEqual($coll[0]->alias1, 'someone'); - $this->assertEqual($coll[0]->alias2, 187); + $this->assertEqual($coll[0]->alias1, 'first'); + $this->assertEqual($coll[0]->alias2, 123); + $this->assertEqual($coll[0]->anotherField, 'camelCase'); } + public function testAliasesAreSupportedForDqlWherePart() { $q = new Doctrine_Query(); - $q->select('c.alias1, c.alias2') + $q->select('c.alias1, c.alias2, c.anotherField') ->from('ColumnAliasTest c') - ->where('c.alias1 = ?'); + ->where('c.anotherField = ?'); - $coll = $q->execute(array('someone')); + $coll = $q->execute(array('KoQ')); - $this->assertEqual($coll[0]->alias1, 'someone'); - $this->assertEqual($coll[0]->alias2, 187); + $this->assertEqual($coll[0]->alias1, 'one'); + $this->assertEqual($coll[0]->alias2, 456); + $this->assertEqual($coll[0]->anotherField, 'KoQ'); } + public function testAliasesAreSupportedForDqlAggregateFunctions() { $q = new Doctrine_Query(); - $q->select('MAX(c.alias1)') - ->from('ColumnAliasTest c'); + $q->select('MAX(c.alias2)')->from('ColumnAliasTest c'); $coll = $q->execute(); - $this->assertEqual($coll[0]->max, 'someone'); + $this->assertEqual($coll[0]->MAX, 456); } + public function testAliasesAreSupportedForDqlHavingPart() { $q = new Doctrine_Query(); - $q->select('c.alias1') + $q->select('c.alias2') ->from('ColumnAliasTest c') - ->having('MAX(c.alias2) = 187') - ->groupby('c.id'); + ->groupby('c.id') + ->having('c.alias2 > 123'); $coll = $q->execute(); - $this->assertEqual($coll[0]->alias1, 'someone'); + $this->assertEqual($coll[0]->alias2, 456); } } diff --git a/tests/Export/RecordTestCase.php b/tests/Export/RecordTestCase.php index d4068f9b6..cc944f0ac 100644 --- a/tests/Export/RecordTestCase.php +++ b/tests/Export/RecordTestCase.php @@ -100,8 +100,8 @@ class Doctrine_Export_Record_TestCase extends Doctrine_UnitTestCase $this->assertEqual($this->adapter->pop(), 'COMMIT'); $this->assertEqual($this->adapter->pop(), 'ALTER TABLE cms__category_languages ADD FOREIGN KEY (category_id) REFERENCES cms__category(id) ON DELETE CASCADE'); - $this->assertEqual($this->adapter->pop(), 'CREATE TABLE cms__category (id BIGINT AUTO_INCREMENT, created DATETIME, parent BIGINT, position MEDIUMINT, active BIGINT, INDEX index_parent_idx (parent), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = INNODB'); $this->assertEqual($this->adapter->pop(), 'CREATE TABLE cms__category_languages (id BIGINT AUTO_INCREMENT, name TEXT, category_id BIGINT, language_id BIGINT, INDEX index_category_idx (category_id), INDEX index_language_idx (language_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = INNODB'); + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE cms__category (id BIGINT AUTO_INCREMENT, created DATETIME, parent BIGINT, position MEDIUMINT, active BIGINT, INDEX index_parent_idx (parent), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = INNODB'); $this->assertEqual($this->adapter->pop(), 'BEGIN TRANSACTION'); } diff --git a/tests/run.php b/tests/run.php index 664e494c2..0a028effb 100644 --- a/tests/run.php +++ b/tests/run.php @@ -280,3 +280,4 @@ $data->addTestCase(new Doctrine_Data_Export_TestCase()); $test->addTestCase($data); $test->run(); +