From 34f4ee71faceab5691c2af150c9815a50e7e4235 Mon Sep 17 00:00:00 2001 From: romanb Date: Mon, 12 Jan 2009 13:34:41 +0000 Subject: [PATCH] First tests for basic collection implementation. First experimental use of closures (Currently commented out, because the svn server makes a syntax check against 5.2.x). --- .../Common/Collections/Collection.php | 179 +++++++++--------- lib/Doctrine/DBAL/Driver.php | 2 +- lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php | 6 +- lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 6 +- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 28 +-- .../DBAL/Schema/AbstractSchemaManager.php | 1 - ...chemaManger.php => MySqlSchemaManager.php} | 0 .../ORM/Internal/Hydration/ObjectDriver.php | 10 +- .../Internal/Hydration/StandardHydrator.php | 9 +- lib/Doctrine/ORM/Mapping/ClassMetadata.php | 15 +- .../ORM/Mapping/Driver/AnnotationDriver.php | 14 +- .../Persisters/AbstractEntityPersister.php | 56 +----- lib/Doctrine/ORM/Query.php | 6 +- lib/Doctrine/ORM/Query/ParserResultDummy.php | 2 +- .../ORM/Query/SqlExecutor/Abstract.php | 4 +- .../ORM/Query/SqlExecutor/SingleSelect.php | 4 +- lib/Doctrine/ORM/UnitOfWork.php | 29 ++- tests/AllTests.php | 2 + tests/Common/AllTests.php | 30 +++ tests/Common/Collections/AllTests.php | 30 +++ tests/Common/Collections/CollectionTest.php | 44 +++++ tests/Orm/AllTests.php | 2 + tests/Orm/Functional/BasicCRUDTest.php | 24 ++- .../Orm/Mapping/ClassMetadataFactoryTest.php | 5 +- tests/Orm/Mapping/ClassMetadataTest.php | 12 +- tests/dbproperties.xml.dev | 1 + tests/lib/Doctrine_OrmFunctionalTestCase.php | 7 + tests/lib/Doctrine_OrmFunctionalTestSuite.php | 7 +- tests/lib/Doctrine_TestUtil.php | 5 +- 29 files changed, 318 insertions(+), 222 deletions(-) rename lib/Doctrine/DBAL/Schema/{MySqlSchemaManger.php => MySqlSchemaManager.php} (100%) create mode 100644 tests/Common/AllTests.php create mode 100644 tests/Common/Collections/AllTests.php create mode 100644 tests/Common/Collections/CollectionTest.php diff --git a/lib/Doctrine/Common/Collections/Collection.php b/lib/Doctrine/Common/Collections/Collection.php index 78ad51798..52989b490 100644 --- a/lib/Doctrine/Common/Collections/Collection.php +++ b/lib/Doctrine/Common/Collections/Collection.php @@ -13,8 +13,7 @@ /** * A Collection is a wrapper around a php array and just like a php array a - * collection instance can be a list, a map or a hashmap, depending on how it - * is used. + * collection instance can be a list, a set or a map, depending on how it is used. * * @author robo */ @@ -27,6 +26,15 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre */ protected $_data = array(); + /** + * + * @param $elements + */ + public function __construct(array $elements = array()) + { + $this->_data = $elements; + } + /** * Unwraps the array contained in the Collection instance. * @@ -38,11 +46,11 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * returns the first record in the collection + * returns the first entry in the collection * * @return mixed */ - public function getFirst() + public function first() { return reset($this->_data); } @@ -52,17 +60,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre * * @return mixed */ - public function getLast() - { - return end($this->_data); - } - - /** - * returns the last record in the collection - * - * @return mixed - */ - public function end() + public function last() { return end($this->_data); } @@ -78,10 +76,10 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * Removes an entry from the collection. + * Removes an entry with a specific key from the collection. * * @param mixed $key - * @return boolean + * @return mixed */ public function remove($key) { @@ -104,8 +102,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre /** * __unset() * - * @param string $name - * @since 1.0 + * @param string $key * @return mixed */ public function __unset($key) @@ -113,13 +110,13 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre return $this->remove($key); } + /* ArrayAccess implementation */ + /** - * Check if an offsetExists. - * - * Part of the ArrayAccess implementation. + * Check if an offset exists. * * @param mixed $offset - * @return boolean whether or not this object contains $offset + * @return boolean Whether or not this object contains $offset */ public function offsetExists($offset) { @@ -127,11 +124,10 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * offsetGet an alias of get() + * Gets the element with the given key. * * Part of the ArrayAccess implementation. * - * @see get, __get * @param mixed $offset * @return mixed */ @@ -169,10 +165,12 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre return $this->remove($offset); } + /* END ArrayAccess implementation */ + /** - * Checks whether the collection contains an entity. + * Checks whether the collection contains a specific key/index. * - * @param mixed $key the key of the element + * @param mixed $key The key to check for. * @return boolean */ public function containsKey($key) @@ -181,14 +179,30 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * Enter description here... + * Checks whether the given element is contained in the collection. + * Only element values are compared, not keys. The comparison of two elements + * is strict, that means not only the value but also the type must match. + * For objects this means reference equality. * - * @param unknown_type $entity - * @return unknown + * @param mixed $element + * @return boolean */ - public function contains($entity) + public function contains($element) { - return in_array($entity, $this->_data, true); + return in_array($element, $this->_data, true); + } + + /** + * Tests for the existance of an element that satisfies the given predicate. + * + * @param function $func + * @return boolean + */ + public function exists($func) { + foreach ($this->_data as $key => $element) + if ($func($key, $element)) + return true; + return false; } /** @@ -203,20 +217,24 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** + * Searches for a given element and, if found, returns the corresponding key/index + * of that element. The comparison of two elements is strict, that means not + * only the value but also the type must match. + * For objects this means reference equality. * + * @param mixed $element The element to search for. + * @return mixed The key/index of the element or FALSE if the element was not found. */ - public function search($record) + public function search($element) { - return array_search($record, $this->_data, true); + return array_search($element, $this->_data, true); } /** - * returns a record for given key + * Gets the element with the given key/index. * - * Collection also maps referential information to newly created records - * - * @param mixed $key the key of the element - * @return Doctrine_Entity return a specified record + * @param mixed $key The key. + * @return mixed The element or NULL, if no element exists for the given key. */ public function get($key) { @@ -227,8 +245,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * Gets all keys. - * (Map method) + * Gets all keys/indexes. * * @return array */ @@ -238,22 +255,21 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * Gets all values. - * (Map method) + * Gets all elements. * * @return array */ - public function getValues() + public function getElements() { return array_values($this->_data); } /** - * Returns the number of records in this collection. + * Returns the number of elements in the collection. * * Implementation of the Countable interface. * - * @return integer The number of records in the collection. + * @return integer The number of elements in the collection. */ public function count() { @@ -261,46 +277,29 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** + * Adds/sets an element in the collection at the index / with the specified key. + * * When the collection is a Map this is like put(key,value)/add(key,value). * When the collection is a List this is like add(position,value). * * @param integer $key * @param mixed $value - * @return void */ public function set($key, $value) { - if ( ! $value instanceof Doctrine_ORM_Entity) { - throw new Doctrine_Collection_Exception('Value variable in set is not an instance of Doctrine_Entity'); - } $this->_data[$key] = $value; - //TODO: Register collection as dirty with the UoW if necessary - $this->_changed(); } /** - * Adds an entry to the collection. + * Adds an element to the collection. * * @param mixed $value * @param string $key - * @return boolean + * @return boolean Always returns TRUE. */ - public function add($value, $key = null) + public function add($value) { - // TODO: Really prohibit duplicates? - if (in_array($value, $this->_data, true)) { - return false; - } - - if (isset($key)) { - if (isset($this->_data[$key])) { - return false; - } - $this->_data[$key] = $value; - } else { - $this->_data[] = $value; - } - + $this->_data[] = $value; return true; } @@ -316,6 +315,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre /** * Checks whether the collection is empty. + * Note: This is preferrable over count() == 0. * * @return boolean TRUE if the collection is empty, FALSE otherwise. */ @@ -326,9 +326,10 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * getIterator + * Gets an iterator that enables foreach() iteration over the elements in + * the collection. * - * @return object ArrayIterator + * @return ArrayIterator */ public function getIterator() { @@ -337,27 +338,25 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre } /** - * @todo Experiment. Waiting for 5.3 closures. - * Example usage: - * - * $map = $coll->mapElements(function($key, $entity) { - * return array($entity->id, $entity->name); - * }); - * - * or: - * - * $map = $coll->mapElements(function($key, $entity) { - * return array($entity->name, strtoupper($entity->name)); - * }); + * Applies the given function to each element in the collection and returns + * a new collection with the modified values. * + * @param function $func */ - public function mapElements($lambda) { - $result = array(); - foreach ($this->_data as $key => $entity) { - list($key, $value) = each($lambda($key, $entity)); - $result[$key] = $value; - } - return $result; + public function map($func) + { + return new Doctrine_Common_Collections_Collection(array_map($func, $this->_data)); + } + + /** + * Applies the given function to each element in the collection and returns + * a new collection with the new values. + * + * @param function $func + */ + public function filter($func) + { + return new Doctrine_Common_Collections_Collection(array_filter($this->_data, $func)); } /** diff --git a/lib/Doctrine/DBAL/Driver.php b/lib/Doctrine/DBAL/Driver.php index 2739f62b3..6f483760b 100644 --- a/lib/Doctrine/DBAL/Driver.php +++ b/lib/Doctrine/DBAL/Driver.php @@ -30,7 +30,7 @@ interface Doctrine_DBAL_Driver * Gets the SchemaManager that can be used to inspect and change the underlying * database schema of the platform this driver connects to. * - * @return Doctrine::DBAL::SchemaManager + * @return Doctrine\DBAL\SchemaManager */ public function getSchemaManager(Doctrine_DBAL_Connection $conn); } diff --git a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php index f2ddd2005..855985d21 100644 --- a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php @@ -44,12 +44,12 @@ class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver public function getDatabasePlatform() { - return new Doctrine_DatabasePlatform_MySqlPlatform(); + return new Doctrine_DBAL_Platforms_MySqlPlatform(); } - public function getSchemaManager(Doctrine_Connection $conn) + public function getSchemaManager(Doctrine_DBAL_Connection $conn) { - return new Doctrine_Schema_MySqlSchemaManager($conn); + return new Doctrine_DBAL_Schema_MySqlSchemaManager($conn); } } diff --git a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php index ff9b546a6..ac475b415 100644 --- a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -31,12 +31,12 @@ class Doctrine_DBAL_Driver_PDOPgSql_Driver implements Doctrine_DBAL_Driver public function getDatabasePlatform() { - return new Doctrine_DatabasePlatform_PostgreSqlPlatform(); + return new Doctrine_DBAL_Platforms_PostgreSqlPlatform(); } - public function getSchemaManager(Doctrine_Connection $conn) + public function getSchemaManager(Doctrine_DBAL_Connection $conn) { - return new Doctrine_Schema_PostgreSqlSchemaManager($conn); + return new Doctrine_DBAL_Schema_PostgreSqlSchemaManager($conn); } } diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 1e8a30eab..49caf5f42 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -724,7 +724,7 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst // attach all primary keys if (isset($options['primary']) && ! empty($options['primary'])) { $keyColumns = array_values($options['primary']); - $keyColumns = array_map(array($this->_conn, 'quoteIdentifier'), $keyColumns); + $keyColumns = array_map(array($this, 'quoteIdentifier'), $keyColumns); $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } @@ -751,9 +751,9 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst // get the type of the table if (isset($options['type'])) { $type = $options['type']; - } else { + }/* else { $type = $this->getAttribute(Doctrine::ATTR_DEFAULT_TABLE_TYPE); - } + }*/ if ($type) { $optionStrings[] = 'ENGINE = ' . $type; @@ -1057,13 +1057,13 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst } /** @override */ - public function getSmallIntDeclarationSql(array $field) + public function getSmallIntTypeDeclarationSql(array $field) { return 'SMALLINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); } /** @override */ - public function getMediumIntDeclarationSql(array $field) + public function getMediumIntTypeDeclarationSql(array $field) { return 'MEDIUMINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); } @@ -1072,23 +1072,23 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) { $default = $autoinc = ''; - if ( ! empty($field['autoincrement'])) { + if ( ! empty($columnDef['autoincrement'])) { $autoinc = ' AUTO_INCREMENT'; - } elseif (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) ? null : 0; + } elseif (array_key_exists('default', $columnDef)) { + if ($columnDef['default'] === '') { + $columnDef['default'] = empty($columnDef['notnull']) ? null : 0; } - if (is_null($field['default'])) { + if (is_null($columnDef['default'])) { $default = ' DEFAULT NULL'; } else { - $default = ' DEFAULT '.$this->quote($field['default']); + $default = ' DEFAULT '.$this->quote($columnDef['default']); } - } elseif (empty($field['notnull'])) { + } elseif (empty($columnDef['notnull'])) { $default = ' DEFAULT NULL'; } - $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; - $unsigned = (isset($field['unsigned']) && $field['unsigned']) ? ' UNSIGNED' : ''; + $notnull = (isset($columnDef['notnull']) && $columnDef['notnull']) ? ' NOT NULL' : ''; + $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : ''; return $unsigned . $default . $notnull . $autoinc; } diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 92656ae7f..1feeaa8c5 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -172,7 +172,6 @@ abstract class Doctrine_DBAL_Schema_AbstractSchemaManager } /** - * dropTable * drop an existing table * * @param string $table name of table that should be dropped from the database diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php similarity index 100% rename from lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php rename to lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectDriver.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectDriver.php index ef4c18582..782958884 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectDriver.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectDriver.php @@ -65,7 +65,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver // check needed because of mixed results. // is_object instead of is_array because is_array is slow on large arrays. if (is_object($coll)) { - $coll->end(); + $coll->last(); return $coll->key(); } else { end($coll); @@ -121,7 +121,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver $classMetadata1 = $this->_metadataMap[spl_object_hash($entity1)]; $classMetadata2 = $this->_metadataMap[spl_object_hash($entity2)]; $indexValue = $classMetadata2->getReflectionProperty($indexField)->getValue($entity2); - $classMetadata1->getReflectionProperty($property)->getValue($entity1)->add($entity2, $indexValue); + $classMetadata1->getReflectionProperty($property)->getValue($entity1)->set($indexValue, $entity2); } /** @@ -196,7 +196,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver public function addElementToIndexedCollection($coll, $entity, $keyField) { - $coll->add($entity, $this->getFieldValue($entity, $keyField)); + $coll->set($entity, $this->getFieldValue($keyField, $entity)); } public function addElementToCollection($coll, $entity) @@ -216,7 +216,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver */ public function updateResultPointer(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne) { - if ($coll === /*$this->_nullObject*/null) { + if ($coll === null) { echo "HERE!"; unset($resultPointers[$dqlAlias]); // Ticket #1228 return; @@ -232,7 +232,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver $resultPointers[$dqlAlias] =& $coll[key($coll)]; } else if ($coll instanceof Doctrine_ORM_Collection) { if (count($coll) > 0) { - $resultPointers[$dqlAlias] = $coll->getLast(); + $resultPointers[$dqlAlias] = $coll->last(); } } else { $resultPointers[$dqlAlias] = $coll; diff --git a/lib/Doctrine/ORM/Internal/Hydration/StandardHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/StandardHydrator.php index 67cdb6146..d81b19bef 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/StandardHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/StandardHydrator.php @@ -105,19 +105,18 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte $rootEntityName = $this->_queryComponents[$rootAlias]['metadata']->getClassName(); // if only one class is involved we can make our lives easier $isSimpleQuery = count($this->_queryComponents) <= 1; - // Lookup map to quickly discover/lookup existing records in the result + // Lookup map to quickly discover/lookup existing entities in the result // It's the identifier "memory" $identifierMap = array(); // Holds for each class a pointer to the last previously seen element in the result set $resultPointers = array(); - // holds the values of the identifier/primary key fields of components, - // separated by a pipe '|' and grouped by component alias (r, u, i, ... whatever) - // the $idTemplate is a prepared template. $id is set to a fresh template when + // Holds the values of the identifier/primary key fields of entities, + // separated by a pipe '|' and grouped by DQL class alias (r, u, i, ... whatever) + // The $idTemplate is a prepared template. $id is set to a fresh template when // starting to process a row. $id = array(); $idTemplate = array(); - // Holds the resulting hydrated data structure if ($parserResult->isMixedQuery() || $hydrationMode == Doctrine_ORM_Query::HYDRATE_SCALAR) { $result = array(); } else { diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index a42efdd69..760d58e60 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -343,11 +343,6 @@ class Doctrine_ORM_Mapping_ClassMetadata $this->_tableName = $this->_entityName; $this->_rootEntityName = $entityName; $this->_reflectionClass = new ReflectionClass($entityName); - $reflectionProps = $this->_reflectionClass->getProperties(); - foreach ($reflectionProps as $prop) { - $prop->setAccessible(true); - $this->_reflectionProperties[$prop->getName()] = $prop; - } } /** @@ -652,6 +647,11 @@ class Doctrine_ORM_Mapping_ClassMetadata $this->_isIdentifierComposite = true; } } + + // Store ReflectionProperty of mapped field + $refProp = $this->_reflectionClass->getProperty($mapping['fieldName']); + $refProp->setAccessible(true); + $this->_reflectionProperties[$mapping['fieldName']] = $refProp; } private function _validateAndCompleteClassMapping(array &$mapping) @@ -1270,6 +1270,11 @@ class Doctrine_ORM_Mapping_ClassMetadata } $this->_associationMappings[$sourceFieldName] = $assocMapping; $this->_registerMappingIfInverse($assocMapping); + + // Store ReflectionProperty of mapped field + $refProp = $this->_reflectionClass->getProperty($sourceFieldName); + $refProp->setAccessible(true); + $this->_reflectionProperties[$sourceFieldName] = $refProp; } /** diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 7888bebf6..245afacde 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -50,9 +50,6 @@ class Doctrine_ORM_Mapping_Driver_AnnotationDriver { } foreach ($annotClass->getProperties() as $property) { - if ($property->hasAnnotation('DoctrineTransient')) { - continue; - } $mapping = array(); $mapping['fieldName'] = $property->getName(); if ($columnAnnot = $property->getAnnotation('DoctrineColumn')) { @@ -90,8 +87,6 @@ class Doctrine_ORM_Mapping_Driver_AnnotationDriver { $mapping['joinTable'] = $manyToManyAnnot->joinTable; $mapping['mappedBy'] = $manyToManyAnnot->mappedBy; $metadata->mapManyToMany($mapping); - } else { - throw new Doctrine_ORM_Exceptions_MappingException($className); } } } @@ -112,9 +107,16 @@ final class DoctrineDiscriminatorColumn extends Annotation { } final class DoctrineDiscriminatorMap extends Annotation {} final class DoctrineSubClasses extends Annotation {} -final class DoctrineTransient extends Annotation {} final class DoctrineId extends Annotation {} final class DoctrineIdGenerator extends Annotation {} +final class DoctrineVersion extends Annotation {} +final class DoctrineJoinColumn extends Annotation { + public $name; + public $type; + public $length; + public $onDelete; + public $onUpdate; +} final class DoctrineColumn extends Annotation { public $type; public $length; diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php index 385f7482b..39312b5c1 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php @@ -101,7 +101,6 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister * Updates an entity. * * @param object $entity The entity to update. - * @return void */ public function update($entity) { @@ -110,30 +109,12 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister $id = array_combine($this->_classMetadata->getIdentifierFieldNames(), $this->_em->getUnitOfWork()->getEntityIdentifier($entity)); $this->_conn->update($this->_classMetadata->getTableName(), $updateData, $id); - - /*$dataChangeSet = $entity->_getDataChangeSet(); - $referenceChangeSet = $entity->_getReferenceChangeSet(); - - foreach ($referenceChangeSet as $field => $change) { - $assocMapping = $entity->getClass()->getAssociationMapping($field); - if ($assocMapping instanceof Doctrine_Association_OneToOneMapping) { - if ($assocMapping->isInverseSide()) { - continue; // ignore inverse side - } - // ... null out the foreign key - - } - //... - } - */ - //TODO: perform update } /** * Deletes an entity. * * @param object $entity The entity to delete. - * @return void */ public function delete($entity) { @@ -141,40 +122,11 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister $this->_em->getUnitOfWork()->getEntityIdentifier($entity)); $this->_conn->delete($this->_classMetadata->getTableName(), $id); } - + /** - * Inserts a row into a table. * - * @todo This method could be used to allow mapping to secondary table(s). - * @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable + * @return */ - protected function _insertRow($tableName, array $data) - { - $this->_conn->insert($tableName, $data); - } - - /** - * Deletes rows of a table. - * - * @todo This method could be used to allow mapping to secondary table(s). - * @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable - */ - protected function _deleteRow($tableName, array $identifierToMatch) - { - $this->_conn->delete($tableName, $identifierToMatch); - } - - /** - * Deletes rows of a table. - * - * @todo This method could be used to allow mapping to secondary table(s). - * @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable - */ - protected function _updateRow($tableName, array $data, array $identifierToMatch) - { - $this->_conn->update($tableName, $data, $identifierToMatch); - } - public function getClassMetadata() { return $this->_classMetadata; @@ -258,7 +210,6 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister //echo "NOT TO-ONE OR INVERSE!"; continue; } - //echo "HERE!!!"; foreach ($assocMapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) { //TODO: throw exc if field not set $otherClass = $this->_em->getClassMetadata($assocMapping->getTargetEntityName()); @@ -283,7 +234,4 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister $result[$discColumn['name']] = array_search($this->_entityName, $discMap); } } - - abstract protected function _doUpdate(Doctrine_ORM_Entity $entity); - abstract protected function _doInsert(Doctrine_ORM_Entity $entity); } diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 0a86dded7..6cbd0896b 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -226,12 +226,12 @@ class Doctrine_ORM_Query extends Doctrine_ORM_Query_Abstract } /** - * Executes the query and populates the data set. + * Executes the query. * * @param string $params Parameters to be sent to query. * @param integer $hydrationMode Doctrine processing mode to be used during hydration process. * One of the Doctrine::HYDRATE_* constants. - * @return Doctrine_Collection The root collection + * @return mixed */ public function execute($params = array(), $hydrationMode = null) { @@ -331,7 +331,7 @@ class Doctrine_ORM_Query extends Doctrine_ORM_Query_Abstract // Double the params if we are using limit-subquery algorithm // We always have an instance of Doctrine_ORM_Query_ParserResult on hands... if ($this->_parserResult->isLimitSubqueryUsed() && - $this->_entityManager->getConnection()->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') { + $this->_entityManager->getConnection()->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') { $params = array_merge($params, $params); } diff --git a/lib/Doctrine/ORM/Query/ParserResultDummy.php b/lib/Doctrine/ORM/Query/ParserResultDummy.php index 88a99ad8d..2dbfa61eb 100644 --- a/lib/Doctrine/ORM/Query/ParserResultDummy.php +++ b/lib/Doctrine/ORM/Query/ParserResultDummy.php @@ -2,7 +2,7 @@ /** * This class is just an intermediate implementation for refactoring purposes - * and will be replaced by the ParserResult class of the new DQL parser branch. + * and will be replaced by the ParserResult class of the new DQL parser. * */ class Doctrine_ORM_Query_ParserResultDummy diff --git a/lib/Doctrine/ORM/Query/SqlExecutor/Abstract.php b/lib/Doctrine/ORM/Query/SqlExecutor/Abstract.php index ff97359e6..402df2b03 100644 --- a/lib/Doctrine/ORM/Query/SqlExecutor/Abstract.php +++ b/lib/Doctrine/ORM/Query/SqlExecutor/Abstract.php @@ -57,13 +57,13 @@ abstract class Doctrine_ORM_Query_SqlExecutor_Abstract implements Serializable * @param Doctrine_Connection $conn The database connection that is used to execute the queries. * @param array $params The parameters. */ - abstract public function execute(Doctrine_Connection $conn, array $params); + abstract public function execute(Doctrine_DBAL_Connection $conn, array $params); /** * Factory method. * Creates an appropriate sql executor for the given AST. * - * @param Doctrine_ORM_Query_Production $AST The root node of the AST. + * @param Doctrine_ORM_Query_AST $AST The root node of the AST. * @return Doctrine_ORM_Query_SqlExecutor_Abstract The executor that is suitable for the given AST. */ public static function create(Doctrine_ORM_Query_AST $AST) diff --git a/lib/Doctrine/ORM/Query/SqlExecutor/SingleSelect.php b/lib/Doctrine/ORM/Query/SqlExecutor/SingleSelect.php index 643d5b576..abd6242d6 100644 --- a/lib/Doctrine/ORM/Query/SqlExecutor/SingleSelect.php +++ b/lib/Doctrine/ORM/Query/SqlExecutor/SingleSelect.php @@ -25,7 +25,7 @@ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @author Roman Borschel * @version $Revision$ - * @link www.phpdoctrine.org + * @link www.doctrine-project.org * @since 2.0 */ class Doctrine_ORM_Query_SqlExecutor_SingleSelect extends Doctrine_ORM_Query_SqlExecutor_Abstract @@ -36,7 +36,7 @@ class Doctrine_ORM_Query_SqlExecutor_SingleSelect extends Doctrine_ORM_Query_Sql $this->_sqlStatements = $AST->buildSql(); } - public function execute(Doctrine_Connection $conn, array $params) + public function execute(Doctrine_DBAL_Connection $conn, array $params) { return $conn->execute($this->_sqlStatements, $params); } diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 3b239b1d1..e6e84653f 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -452,23 +452,21 @@ class Doctrine_ORM_UnitOfWork * @return array */ private function _getCommitOrder(array $entityChangeSet = null) - { - //TODO: Once these 3 arrays are indexed by classname we can do this: - // Either way... do we need to care about duplicates? - /*$classesInChangeSet = array_merge( - array_keys($this->_newEntities), - array_keys($this->_dirtyEntities), - array_keys($this->_deletedEntities) - );*/ - + { if (is_null($entityChangeSet)) { - $entityChangeSet = array_merge($this->_newEntities, $this->_dirtyEntities, $this->_deletedEntities); + $entityChangeSet = array_merge( + $this->_newEntities, + $this->_dirtyEntities, + $this->_deletedEntities); } /* if (count($entityChangeSet) == 1) { * return array($entityChangeSet[0]->getClass()); * } */ + + // TODO: We can cache computed commit orders in the metadata cache! + // Check cache at this point here! // See if there are any new classes in the changeset, that are not in the // commit order graph yet (dont have a node). @@ -1242,6 +1240,17 @@ class Doctrine_ORM_UnitOfWork } return false; } + + /** + * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the + * number of entities in the identity map. + */ + public function size() + { + $count = 0; + foreach ($this->_identityMap as $entitySet) $count += count($entitySet); + return $count; + } } diff --git a/tests/AllTests.php b/tests/AllTests.php index d22a41e5b..906cf02f5 100644 --- a/tests/AllTests.php +++ b/tests/AllTests.php @@ -7,6 +7,7 @@ if (!defined('PHPUnit_MAIN_METHOD')) { require_once 'lib/DoctrineTestInit.php'; // Suites +require_once 'Common/AllTests.php'; require_once 'Dbal/AllTests.php'; require_once 'Orm/AllTests.php'; @@ -21,6 +22,7 @@ class AllTests { $suite = new Doctrine_TestSuite('Doctrine Tests'); + $suite->addTest(Common_AllTests::suite()); $suite->addTest(Dbal_AllTests::suite()); $suite->addTest(Orm_AllTests::suite()); diff --git a/tests/Common/AllTests.php b/tests/Common/AllTests.php new file mode 100644 index 000000000..b56dfde07 --- /dev/null +++ b/tests/Common/AllTests.php @@ -0,0 +1,30 @@ +addTest(Common_Collections_AllTests::suite()); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'Common_AllTests::main') { + Common_AllTests::main(); +} \ No newline at end of file diff --git a/tests/Common/Collections/AllTests.php b/tests/Common/Collections/AllTests.php new file mode 100644 index 000000000..8b8840b4e --- /dev/null +++ b/tests/Common/Collections/AllTests.php @@ -0,0 +1,30 @@ +addTestSuite('Common_Collections_CollectionTest'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'Common_Collections_AllTests::main') { + Common_Collections_AllTests::main(); +} \ No newline at end of file diff --git a/tests/Common/Collections/CollectionTest.php b/tests/Common/Collections/CollectionTest.php new file mode 100644 index 000000000..60587ea36 --- /dev/null +++ b/tests/Common/Collections/CollectionTest.php @@ -0,0 +1,44 @@ +_coll = new Doctrine_Common_Collections_Collection; + } + + /*public function testExists() { + $this->_coll->add("one"); + $this->_coll->add("two"); + $exists = $this->_coll->exists(function($key, $element) { return $element == "one"; }); + $this->assertTrue($exists); + $exists = $this->_coll->exists(function($key, $element) { return $element == "other"; }); + $this->assertFalse($exists); + } + + public function testMap() { + $this->_coll->add(1); + $this->_coll->add(2); + $res = $this->_coll->map(function ($e) { return $e * 2; }); + $this->assertEquals(array(2, 4), $res->unwrap()); + } + + public function testFilter() { + $this->_coll->add(1); + $this->_coll->add("foo"); + $this->_coll->add(3); + $res = $this->_coll->filter(function ($e) { return is_numeric($e); }); + $this->assertEquals(array(0 => 1, 2 => 3), $res->unwrap()); + }*/ +} + diff --git a/tests/Orm/AllTests.php b/tests/Orm/AllTests.php index d04f53d0f..d37abca02 100644 --- a/tests/Orm/AllTests.php +++ b/tests/Orm/AllTests.php @@ -12,6 +12,7 @@ require_once 'Orm/Ticket/AllTests.php'; require_once 'Orm/Entity/AllTests.php'; require_once 'Orm/Associations/AllTests.php'; require_once 'Orm/Mapping/AllTests.php'; +require_once 'Orm/Functional/AllTests.php'; // Tests require_once 'Orm/UnitOfWorkTest.php'; @@ -41,6 +42,7 @@ class Orm_AllTests $suite->addTest(Orm_Ticket_AllTests::suite()); $suite->addTest(Orm_Associations_AllTests::suite()); $suite->addTest(Orm_Mapping_AllTests::suite()); + $suite->addTest(Orm_Functional_AllTests::suite()); return $suite; } diff --git a/tests/Orm/Functional/BasicCRUDTest.php b/tests/Orm/Functional/BasicCRUDTest.php index 49489cc13..4e68dbc40 100644 --- a/tests/Orm/Functional/BasicCRUDTest.php +++ b/tests/Orm/Functional/BasicCRUDTest.php @@ -8,13 +8,14 @@ require_once 'lib/DoctrineTestInit.php'; * @author robo */ class Orm_Functional_BasicCRUDTest extends Doctrine_OrmFunctionalTestCase { - public function testSingleEntityCRUD() { - $em = $this->_getEntityManager(); - $exporter = new Doctrine_ORM_Export_ClassExporter($em); + public function testSingleEntityCRUD() { + $em = $this->_em; + + $exporter = new Doctrine_ORM_Export_ClassExporter($this->_em); $exporter->exportClasses(array( - $em->getClassMetadata('CmsUser'), - $em->getClassMetadata('CmsPhonenumber') + $this->_em->getClassMetadata('CmsUser'), + $this->_em->getClassMetadata('CmsPhonenumber') )); // Create @@ -46,11 +47,20 @@ class Orm_Functional_BasicCRUDTest extends Doctrine_OrmFunctionalTestCase { $this->assertTrue($em->getUnitOfWork()->isRegisteredRemoved($user)); $em->flush(); $this->assertFalse($em->getUnitOfWork()->isRegisteredRemoved($user)); - } public function testMore() { - + echo PHP_EOL . "SECOND" . PHP_EOL; + /*$user = new CmsUser; + $user->name = 'jon'; + $user->*/ + + $ph = new CmsPhonenumber; + $ph->phonenumber = 123456; + + $this->_em->save($ph); + + $this->_em->flush(); } } diff --git a/tests/Orm/Mapping/ClassMetadataFactoryTest.php b/tests/Orm/Mapping/ClassMetadataFactoryTest.php index 6e7f24578..1b93ad84a 100644 --- a/tests/Orm/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Orm/Mapping/ClassMetadataFactoryTest.php @@ -134,7 +134,10 @@ class ClassMetadataFactoryTestSubject extends Doctrine_ORM_Mapping_ClassMetadata /* Test classes */ -class CMFTest_Entity1 {} +class CMFTest_Entity1 { + protected $name; + protected $other; +} class CMFTest_Entity2 extends CMFTest_Entity1 {} class CMFTest_Entity3 extends CMFTest_Entity2 {} diff --git a/tests/Orm/Mapping/ClassMetadataTest.php b/tests/Orm/Mapping/ClassMetadataTest.php index 404fff836..0f79072f0 100644 --- a/tests/Orm/Mapping/ClassMetadataTest.php +++ b/tests/Orm/Mapping/ClassMetadataTest.php @@ -10,7 +10,7 @@ class Orm_Mapping_ClassMetadataTest extends Doctrine_OrmTestCase $cm = new Doctrine_ORM_Mapping_ClassMetadata('CmsUser'); // Test initial state - $this->assertTrue(count($cm->getReflectionProperties()) > 0); + $this->assertTrue(count($cm->getReflectionProperties()) == 0); $this->assertTrue($cm->getReflectionClass() instanceof ReflectionClass); $this->assertEquals('CmsUser', $cm->getClassName()); $this->assertEquals('CmsUser', $cm->getRootClassName()); @@ -22,8 +22,8 @@ class Orm_Mapping_ClassMetadataTest extends Doctrine_OrmTestCase $cm->setParentClasses(array("UserParent")); $cm->setCustomRepositoryClass("UserRepository"); $cm->setDiscriminatorColumn(array('name' => 'disc', 'type' => 'integer')); - $cm->mapOneToOne(array('fieldName' => 'foo', 'targetEntity' => 'Bar', 'mappedBy' => 'foo')); - $this->assertTrue($cm->getAssociationMapping('foo') instanceof Doctrine_ORM_Mapping_OneToOneMapping); + $cm->mapOneToOne(array('fieldName' => 'phonenumbers', 'targetEntity' => 'Bar', 'mappedBy' => 'foo')); + $this->assertTrue($cm->getAssociationMapping('phonenumbers') instanceof Doctrine_ORM_Mapping_OneToOneMapping); $this->assertEquals(1, count($cm->getAssociationMappings())); $serialized = serialize($cm); @@ -38,10 +38,10 @@ class Orm_Mapping_ClassMetadataTest extends Doctrine_OrmTestCase $this->assertEquals(array('UserParent'), $cm->getParentClasses()); $this->assertEquals('UserRepository', $cm->getCustomRepositoryClass()); $this->assertEquals(array('name' => 'disc', 'type' => 'integer'), $cm->getDiscriminatorColumn()); - $this->assertTrue($cm->getAssociationMapping('foo') instanceof Doctrine_ORM_Mapping_OneToOneMapping); + $this->assertTrue($cm->getAssociationMapping('phonenumbers') instanceof Doctrine_ORM_Mapping_OneToOneMapping); $this->assertEquals(1, count($cm->getAssociationMappings())); - $oneOneMapping = $cm->getAssociationMapping('foo'); - $this->assertEquals('foo', $oneOneMapping->getSourceFieldName()); + $oneOneMapping = $cm->getAssociationMapping('phonenumbers'); + $this->assertEquals('phonenumbers', $oneOneMapping->getSourceFieldName()); $this->assertEquals('Bar', $oneOneMapping->getTargetEntityName()); } diff --git a/tests/dbproperties.xml.dev b/tests/dbproperties.xml.dev index 9e4f63fa2..5a51b0651 100644 --- a/tests/dbproperties.xml.dev +++ b/tests/dbproperties.xml.dev @@ -18,5 +18,6 @@ + \ No newline at end of file diff --git a/tests/lib/Doctrine_OrmFunctionalTestCase.php b/tests/lib/Doctrine_OrmFunctionalTestCase.php index c298e2a33..238d41f50 100644 --- a/tests/lib/Doctrine_OrmFunctionalTestCase.php +++ b/tests/lib/Doctrine_OrmFunctionalTestCase.php @@ -8,6 +8,8 @@ */ class Doctrine_OrmFunctionalTestCase extends Doctrine_OrmTestCase { + protected $_em; + /** * The currently loaded model names of the fixtures for the testcase. */ @@ -103,13 +105,18 @@ class Doctrine_OrmFunctionalTestCase extends Doctrine_OrmTestCase foreach (array_reverse($this->_loadedFixtures) as $table) { $conn->exec("DELETE FROM " . $table); } + $this->_em->clear(); } protected function setUp() { if ( ! isset($this->sharedFixture['conn'])) { + echo " --- CREATE CONNECTION ----"; $this->sharedFixture['conn'] = Doctrine_TestUtil::getConnection(); } + if ( ! $this->_em) { + $this->_em = $this->_getEntityManager(); + } } protected function _getEntityManager($config = null, $eventManager = null) { diff --git a/tests/lib/Doctrine_OrmFunctionalTestSuite.php b/tests/lib/Doctrine_OrmFunctionalTestSuite.php index 2e3248f75..435b2f753 100644 --- a/tests/lib/Doctrine_OrmFunctionalTestSuite.php +++ b/tests/lib/Doctrine_OrmFunctionalTestSuite.php @@ -13,8 +13,13 @@ class Doctrine_OrmFunctionalTestSuite extends Doctrine_OrmTestSuite { protected function setUp() { + if ( ! isset($this->sharedFixture['conn'])) { + $this->sharedFixture['conn'] = Doctrine_TestUtil::getConnection(); + } } protected function tearDown() - {} + { + $this->sharedFixture = null; + } } \ No newline at end of file diff --git a/tests/lib/Doctrine_TestUtil.php b/tests/lib/Doctrine_TestUtil.php index 5dfdb5f33..ba282c0f4 100644 --- a/tests/lib/Doctrine_TestUtil.php +++ b/tests/lib/Doctrine_TestUtil.php @@ -7,13 +7,14 @@ class Doctrine_TestUtil public static function getConnection() { if (isset($GLOBALS['db_type'], $GLOBALS['db_username'], $GLOBALS['db_password'], - $GLOBALS['db_host'], $GLOBALS['db_name'])) { + $GLOBALS['db_host'], $GLOBALS['db_name'], $GLOBALS['db_port'])) { $params = array( 'driver' => $GLOBALS['db_type'], 'user' => $GLOBALS['db_username'], 'password' => $GLOBALS['db_password'], 'host' => $GLOBALS['db_host'], - 'database' => $GLOBALS['db_name'] + 'dbname' => $GLOBALS['db_name'], + 'port' => $GLOBALS['db_port'] ); } else { $params = array(