From 080f73733859e0588108467ba7fda2b10ae7be68 Mon Sep 17 00:00:00 2001 From: "Roman S. Borschel" Date: Sat, 1 May 2010 12:14:16 +0200 Subject: [PATCH 1/8] [DDC-534] Fixed. --- lib/Doctrine/ORM/UnitOfWork.php | 10 ++++++++-- tests/Doctrine/Tests/ORM/UnitOfWorkTest.php | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 4a0c5663f..2f5167d08 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -485,7 +485,7 @@ class UnitOfWork implements PropertyChangedListener } } } - + // Look for changes in associations of the entity foreach ($class->associationMappings as $assoc) { $val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity); @@ -2042,9 +2042,15 @@ class UnitOfWork implements PropertyChangedListener $oid = spl_object_hash($entity); $class = $this->_em->getClassMetadata(get_class($entity)); + $isAssocField = isset($class->associationMappings[$propertyName]); + + if ( ! $isAssocField && ! isset($class->fieldMappings[$propertyName])) { + return; // ignore non-persistent fields + } + $this->_entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue); - if (isset($class->associationMappings[$propertyName])) { + if ($isAssocField) { $assoc = $class->associationMappings[$propertyName]; if ($assoc->isOneToOne() && $assoc->isOwningSide) { $this->_entityUpdates[$oid] = $entity; diff --git a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php index 2ace68f0b..12b9c1ea0 100644 --- a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php +++ b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php @@ -140,6 +140,7 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase $this->assertTrue($this->_unitOfWork->isInIdentityMap($entity)); $entity->setData('newdata'); + $entity->setTransient('newtransientvalue'); $this->assertTrue($this->_unitOfWork->isScheduledForUpdate($entity)); @@ -206,10 +207,19 @@ class NotifyChangedEntity implements \Doctrine\Common\NotifyPropertyChanged */ private $data; + private $transient; // not persisted + public function getId() { return $this->id; } + public function setTransient($value) { + if ($value != $this->transient) { + $this->_onPropertyChanged('transient', $this->transient, $value); + $this->transient = $value; + } + } + public function getData() { return $this->data; } From 3001d26ad45d02b12076c1a2574b4df676bc4484 Mon Sep 17 00:00:00 2001 From: "Jonathan H. Wage" Date: Wed, 5 May 2010 15:14:48 -0400 Subject: [PATCH 2/8] Fixing typo/mistake. Test coming soon. --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index d1f13f002..a6100856c 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -395,7 +395,7 @@ class ClassMetadataInfo public function getReflectionClass() { if ( ! $this->reflClass) { - $this->reflClass = new ReflectionClass($entityName); + $this->reflClass = new ReflectionClass($this->name); } return $this->reflClass; } From 8d52967fcd8a5d956fa0b7327fe1b89a690a6c79 Mon Sep 17 00:00:00 2001 From: "Roman S. Borschel" Date: Fri, 7 May 2010 13:36:25 +0200 Subject: [PATCH 3/8] Polished QueryBuilder API documentation and added another test. --- lib/Doctrine/ORM/EntityManager.php | 5 - lib/Doctrine/ORM/QueryBuilder.php | 298 ++++++++++-------- tests/Doctrine/Tests/ORM/QueryBuilderTest.php | 19 +- 3 files changed, 187 insertions(+), 135 deletions(-) diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index c4aa9bb55..871bc62fa 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -1,7 +1,5 @@ * @author Guilherme Blanco * @author Jonathan Wage diff --git a/lib/Doctrine/ORM/QueryBuilder.php b/lib/Doctrine/ORM/QueryBuilder.php index fcfe873d8..e547814ff 100644 --- a/lib/Doctrine/ORM/QueryBuilder.php +++ b/lib/Doctrine/ORM/QueryBuilder.php @@ -1,7 +1,5 @@ - * @author Jonathan Wage - * @author Roman Borschel + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ class QueryBuilder { + /* The query types. */ const SELECT = 0; const DELETE = 1; const UPDATE = 2; + /** The builder states. */ const STATE_DIRTY = 0; const STATE_CLEAN = 1; /** - * @var EntityManager $em The EntityManager used by this QueryBuilder. + * @var EntityManager The EntityManager used by this QueryBuilder. */ private $_em; /** - * @var array $dqlParts The array of DQL parts collected. + * @var array The array of DQL parts collected. */ private $_dqlParts = array( 'select' => array(), @@ -105,13 +102,17 @@ class QueryBuilder /** * Gets an ExpressionBuilder used for object-oriented construction of query expressions. - * Intended for convenient inline usage. Example: + * This producer method is intended for convenient inline usage. Example: * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->where($qb->expr()->eq('u.id', 1)); + * + * + * For more complex expression construction, consider storing the expression + * builder object in a local variable. * * @return Expr */ @@ -141,16 +142,9 @@ class QueryBuilder } /** - * Get the state of this query builder instance + * Get the state of this query builder instance. * - * [php] - * if ($qb->getState() == QueryBuilder::STATE_DIRTY) { - * echo 'Query builder is dirty'; - * } else { - * echo 'Query builder is clean'; - * } - * - * @return integer + * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. */ public function getState() { @@ -158,15 +152,16 @@ class QueryBuilder } /** - * Get the complete DQL string for this query builder instance + * Get the complete DQL string formed by the current specifications of this QueryBuilder. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * echo $qb->getDql(); // SELECT u FROM User u + * * - * @return string The DQL string + * @return string The DQL query string. */ public function getDQL() { @@ -198,14 +193,15 @@ class QueryBuilder } /** - * Constructs a Query instance from the current configuration of the builder. + * Constructs a Query instance from the current specifications of the builder. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u'); * $q = $qb->getQuery(); * $results = $q->execute(); + * * * @return Query */ @@ -218,17 +214,19 @@ class QueryBuilder } /** - * Get the root alias for the query. This is the first entity alias involved - * in the construction of the query + * Gets the root alias of the query. This is the first entity alias involved + * in the construction of the query. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u'); * * echo $qb->getRootAlias(); // u + * * * @return string $rootAlias + * @todo Rename/Refactor: getRootAliases(), there can be multiple roots! */ public function getRootAlias() { @@ -236,14 +234,15 @@ class QueryBuilder } /** - * Sets a query parameter. + * Sets a query parameter for the query being constructed. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->where('u.id = :user_id') * ->setParameter(':user_id', 1); + * * * @param string|integer $key The parameter position or name. * @param mixed $value The parameter value. @@ -256,9 +255,9 @@ class QueryBuilder } /** - * Sets a collection of query parameters. + * Sets a collection of query parameters for the query being constructed. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') @@ -267,8 +266,9 @@ class QueryBuilder * ':user_id1' => 1, * ':user_id2' => 2 * )); + * * - * @param array $params + * @param array $params The query parameters to set. * @return QueryBuilder This QueryBuilder instance. */ public function setParameters(array $params) @@ -278,17 +278,17 @@ class QueryBuilder } /** - * Get all defined parameters + * Gets all defined query parameters for the query being constructed. * - * @return array Defined parameters + * @return array The currently defined query parameters. */ - public function getParameters($params = array()) + public function getParameters() { return $this->_params; } - + /** - * Gets a query parameter. + * Gets a (previously set) query parameter of the query being constructed. * * @param mixed $key The key (index or name) of the bound parameter. * @return mixed The value of the bound parameter. @@ -297,7 +297,7 @@ class QueryBuilder { return isset($this->_params[$key]) ? $this->_params[$key] : null; } - + /** * Sets the position of the first result to retrieve (the "offset"). * @@ -309,10 +309,10 @@ class QueryBuilder $this->_firstResult = $firstResult; return $this; } - + /** * Gets the position of the first result the query object was set to retrieve (the "offset"). - * Returns NULL if {@link setFirstResult} was not applied to this query builder. + * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. * * @return integer The position of the first result. */ @@ -324,7 +324,7 @@ class QueryBuilder /** * Sets the maximum number of results to retrieve (the "limit"). * - * @param integer $maxResults + * @param integer $maxResults The maximum number of results to retrieve. * @return QueryBuilder This QueryBuilder instance. */ public function setMaxResults($maxResults) @@ -345,7 +345,10 @@ class QueryBuilder } /** - * Add a single DQL query part to the array of parts + * Either appends to or replaces a single, generic query part. + * + * The available parts are: 'select', 'from', 'join', 'set', 'where', + * 'groupBy', 'having' and 'orderBy'. * * @param string $dqlPartName * @param string $dqlPart @@ -368,15 +371,17 @@ class QueryBuilder } /** - * Set the SELECT statement + * Specifies an item that is to be returned in the query result. + * Replaces any previously specified selections, if any. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u', 'p') * ->from('User', 'u') * ->leftJoin('u.Phonenumbers', 'p'); + * * - * @param mixed $select String SELECT statement or SELECT Expr instance + * @param mixed $select The selection expressions. * @return QueryBuilder This QueryBuilder instance. */ public function select($select = null) @@ -393,16 +398,17 @@ class QueryBuilder } /** - * Add to the SELECT statement + * Adds an item that is to be returned in the query result. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->addSelect('p') * ->from('User', 'u') * ->leftJoin('u.Phonenumbers', 'p'); + * * - * @param mixed $select String SELECT statement or SELECT Expr instance + * @param mixed $select The selection expression. * @return QueryBuilder This QueryBuilder instance. */ public function addSelect($select = null) @@ -419,16 +425,18 @@ class QueryBuilder } /** - * Construct a DQL DELETE query + * Turns the query being built into a bulk delete query that ranges over + * a certain entity type. * - * [php] + * * $qb = $em->createQueryBuilder() * ->delete('User', 'u') * ->where('u.id = :user_id'); * ->setParameter(':user_id', 1); + * * - * @param string $delete The model to delete - * @param string $alias The alias of the model + * @param string $delete The class/type whose instances are subject to the deletion. + * @param string $alias The class/type alias used in the constructed query. * @return QueryBuilder This QueryBuilder instance. */ public function delete($delete = null, $alias = null) @@ -443,16 +451,18 @@ class QueryBuilder } /** - * Construct a DQL UPDATE query + * Turns the query being built into a bulk update query that ranges over + * a certain entity type. * - * [php] + * * $qb = $em->createQueryBuilder() * ->update('User', 'u') * ->set('u.password', md5('password')) * ->where('u.id = ?'); + * * - * @param string $update The model to update - * @param string $alias The alias of the model + * @param string $update The class/type whose instances are subject to the update. + * @param string $alias The class/type alias used in the constructed query. * @return QueryBuilder This QueryBuilder instance. */ public function update($update = null, $alias = null) @@ -467,12 +477,14 @@ class QueryBuilder } /** - * Specify the FROM part when constructing a SELECT DQL query + * Create and add a query root corresponding to the entity identified by the given alias, + * forming a cartesian product with any existing query roots. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') + * * * @param string $from The class name. * @param string $alias The alias of the class. @@ -482,20 +494,25 @@ class QueryBuilder { return $this->add('from', new Expr\From($from, $alias), true); } - + /** - * Add a INNER JOIN to an associated class. + * Creates and adds a join over an entity association to the query. * - * [php] + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') - * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * * - * @param string $join The relationship to join - * @param string $alias The alias of the join - * @param string $conditionType The condition type constant. Either ON or WITH. - * @param string $condition The condition for the join + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join * @return QueryBuilder This QueryBuilder instance. */ public function join($join, $alias, $conditionType = null, $condition = null) @@ -504,7 +521,11 @@ class QueryBuilder } /** - * Add an INNER JOIN to an associated class. + * Creates and adds a join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. * * [php] * $qb = $em->createQueryBuilder() @@ -512,10 +533,10 @@ class QueryBuilder * ->from('User', 'u') * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); * - * @param string $join The relationship to join - * @param string $alias The alias of the join - * @param string $conditionType The condition type constant. Either ON or WITH. - * @param string $condition The condition for the join + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join * @return QueryBuilder This QueryBuilder instance. */ public function innerJoin($join, $alias, $conditionType = null, $condition = null) @@ -526,19 +547,24 @@ class QueryBuilder } /** - * Add a LEFT JOIN + * Creates and adds a left join over an entity association to the query. * - * [php] + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * * - * @param string $join The relationship to join - * @param string $alias The alias of the join - * @param string $conditionType The condition type constant. Either ON or WITH. - * @param string $condition The condition for the join - * @return QueryBuilder $qb + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join + * @return QueryBuilder This QueryBuilder instance. */ public function leftJoin($join, $alias, $conditionType = null, $condition = null) { @@ -548,17 +574,18 @@ class QueryBuilder } /** - * Add a SET statement for a DQL UPDATE query + * Sets a new value for a field in a bulk update query. * - * [php] + * * $qb = $em->createQueryBuilder() * ->update('User', 'u') * ->set('u.password', md5('password')) * ->where('u.id = ?'); + * * - * @param string $key The key/field to set - * @param string $value The value, expression, placeholder, etc. to use in the SET - * @return QueryBuilder $qb + * @param string $key The key/field to set. + * @param string $value The value, expression, placeholder, etc. + * @return QueryBuilder This QueryBuilder instance. */ public function set($key, $value) { @@ -566,9 +593,10 @@ class QueryBuilder } /** - * Set and override any existing WHERE statements + * Specifies one or more restrictions to the query result. + * Replaces any previously specified restrictions, if any. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') @@ -584,9 +612,10 @@ class QueryBuilder * $qb->update('User', 'u') * ->set('u.password', md5('password')) * ->where($or); + * * - * @param mixed $predicates The predicates. - * @return QueryBuilder + * @param mixed $predicates The restriction predicates. + * @return QueryBuilder This QueryBuilder instance. */ public function where($predicates) { @@ -598,17 +627,19 @@ class QueryBuilder } /** - * Add a new WHERE statement with an AND + * Adds one or more restrictions to the query results, forming a logical + * conjunction with any previously specified restrictions. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->where('u.username LIKE ?') * ->andWhere('u.is_active = 1'); + * * - * @param mixed $where The WHERE statement - * @return QueryBuilder $qb + * @param mixed $where The query restrictions. + * @return QueryBuilder This QueryBuilder instance. * @see where() */ public function andWhere($where) @@ -627,14 +658,16 @@ class QueryBuilder } /** - * Add a new WHERE statement with an OR + * Adds one or more restrictions to the query results, forming a logical + * disjunction with any previously specified restrictions. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->where('u.id = 1') * ->orWhere('u.id = 2'); + * * * @param mixed $where The WHERE statement * @return QueryBuilder $qb @@ -656,16 +689,18 @@ class QueryBuilder } /** - * Set the GROUP BY clause + * Specifies a grouping over the results of the query. + * Replaces any previously specified groupings, if any. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * ->groupBy('u.id'); + * * - * @param string $groupBy The GROUP BY clause - * @return QueryBuilder $qb + * @param string $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. */ public function groupBy($groupBy) { @@ -674,17 +709,18 @@ class QueryBuilder /** - * Add to the existing GROUP BY clause + * Adds a grouping expression to the query. * - * [php] + * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') - * ->groupBy('u.last_login'); - * ->addGroupBy('u.created_at') + * ->groupBy('u.lastLogin'); + * ->addGroupBy('u.createdAt') + * * - * @param string $groupBy The GROUP BY clause - * @return QueryBuilder $qb + * @param string $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. */ public function addGroupBy($groupBy) { @@ -692,10 +728,11 @@ class QueryBuilder } /** - * Set the HAVING clause + * Specifies a restriction over the groups of the query. + * Replaces any previous having restrictions, if any. * - * @param mixed $having - * @return QueryBuilder $qb + * @param mixed $having The restriction over the groups. + * @return QueryBuilder This QueryBuilder instance. */ public function having($having) { @@ -707,10 +744,11 @@ class QueryBuilder } /** - * Add to the existing HAVING clause with an AND + * Adds a restriction over the groups of the query, forming a logical + * conjunction with any existing having restrictions. * - * @param mixed $having - * @return QueryBuilder $qb + * @param mixed $having The restriction to append. + * @return QueryBuilder This QueryBuilder instance. */ public function andHaving($having) { @@ -728,10 +766,11 @@ class QueryBuilder } /** - * Add to the existing HAVING clause with an OR + * Adds a restriction over the groups of the query, forming a logical + * disjunction with any existing having restrictions. * - * @param mixed $having - * @return QueryBuilder $qb + * @param mixed $having The restriction to add. + * @return QueryBuilder This QueryBuilder instance. */ public function orHaving($having) { @@ -749,11 +788,12 @@ class QueryBuilder } /** - * Set the ORDER BY clause + * Specifies an ordering for the query results. + * Replaces any previously specified orderings, if any. * - * @param string $sort What to sort on - * @param string $order Optional: The order to sort the results. - * @return QueryBuilder $qb + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. */ public function orderBy($sort, $order = null) { @@ -762,11 +802,11 @@ class QueryBuilder } /** - * Add to the existing ORDER BY clause + * Adds an ordering to the query results. * - * @param string $sort What to sort on - * @param string $order Optional: The order to sort the results. - * @return QueryBuilder $qb + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. */ public function addOrderBy($sort, $order = null) { @@ -774,10 +814,11 @@ class QueryBuilder } /** - * Get a DQL part or parts by the part name + * Get a query part by its name. * * @param string $queryPartName * @return mixed $queryPart + * @todo Rename: getQueryPart (or remove?) */ public function getDQLPart($queryPartName) { @@ -785,9 +826,10 @@ class QueryBuilder } /** - * Get the full DQL parts array + * Get all query parts. * * @return array $dqlParts + * @todo Rename: getQueryParts (or remove?) */ public function getDQLParts() { @@ -836,6 +878,12 @@ class QueryBuilder . (isset($options['post']) ? $options['post'] : ''); } + /** + * Gets a string representation of this QueryBuilder which corresponds to + * the final DQL query being constructed. + * + * @return string The string representation of this QueryBuilder. + */ public function __toString() { return $this->getDQL(); diff --git a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php index d4a592e65..468e0e20c 100644 --- a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php @@ -1,7 +1,5 @@ * @author Roman Borschel assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) OR (u.id = :uid2)'); } + public function testComplexAndWhereOrWhereNesting() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->orWhere('u.id = :uid2') + ->andWhere('u.id = :uid3') + ->orWhere('u.name = :name1', 'u.name = :name2') + ->andWhere('u.name <> :noname'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((((u.id = :uid) OR (u.id = :uid2)) AND (u.id = :uid3)) OR (u.name = :name1) OR (u.name = :name2)) AND (u.name <> :noname)'); + } + public function testAndWhereIn() { $qb = $this->_em->createQueryBuilder(); From 20c6259fa372349f7c32fe1cd32e6865aaf8ff51 Mon Sep 17 00:00:00 2001 From: Christian Heinrich Date: Wed, 5 May 2010 13:12:38 +0200 Subject: [PATCH 4/8] Corrected method names; the interface already used SQL, the files still used Sql in method names --- .../ORM/Persisters/ManyToManyPersister.php | 24 ++++++++--------- .../ORM/Persisters/OneToManyPersister.php | 26 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index 7ca821930..a182a9859 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -36,7 +36,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * * @override */ - protected function _getDeleteRowSql(PersistentCollection $coll) + protected function _getDeleteRowSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); $joinTable = $mapping->joinTable; @@ -51,7 +51,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * @internal Order of the parameters must be the same as the order of the columns in * _getDeleteRowSql. */ - protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element) + protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) { return $this->_collectJoinTableColumnParameters($coll, $element); } @@ -61,7 +61,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * * @override */ - protected function _getUpdateRowSql(PersistentCollection $coll) + protected function _getUpdateRowSQL(PersistentCollection $coll) {} /** @@ -71,7 +71,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * @internal Order of the parameters must be the same as the order of the columns in * _getInsertRowSql. */ - protected function _getInsertRowSql(PersistentCollection $coll) + protected function _getInsertRowSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); $joinTable = $mapping->joinTable; @@ -87,11 +87,11 @@ class ManyToManyPersister extends AbstractCollectionPersister * @internal Order of the parameters must be the same as the order of the columns in * _getInsertRowSql. */ - protected function _getInsertRowSqlParameters(PersistentCollection $coll, $element) + protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element) { return $this->_collectJoinTableColumnParameters($coll, $element); } - + /** * Collects the parameters for inserting/deleting on the join table in the order * of the join table columns as specified in ManyToManyMapping#joinTableColumns. @@ -105,15 +105,15 @@ class ManyToManyPersister extends AbstractCollectionPersister $params = array(); $mapping = $coll->getMapping(); $isComposite = count($mapping->joinTableColumns) > 2; - + $identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner()); $identifier2 = $this->_uow->getEntityIdentifier($element); - + if ($isComposite) { $class1 = $this->_em->getClassMetadata(get_class($coll->getOwner())); $class2 = $coll->getTypeClass(); } - + foreach ($mapping->joinTableColumns as $joinTableColumn) { if (isset($mapping->relationToSourceKeyColumns[$joinTableColumn])) { if ($isComposite) { @@ -138,7 +138,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * * @override */ - protected function _getDeleteSql(PersistentCollection $coll) + protected function _getDeleteSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); $joinTable = $mapping->joinTable; @@ -157,7 +157,7 @@ class ManyToManyPersister extends AbstractCollectionPersister * @internal Order of the parameters must be the same as the order of the columns in * _getDeleteSql. */ - protected function _getDeleteSqlParameters(PersistentCollection $coll) + protected function _getDeleteSQLParameters(PersistentCollection $coll) { $params = array(); $mapping = $coll->getMapping(); @@ -170,7 +170,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } else { $params[] = array_pop($identifier); } - + return $params; } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index 2bd7925c4..efecd2a50 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -25,7 +25,7 @@ use Doctrine\ORM\PersistentCollection; /** * Persister for one-to-many collections. - * + * * IMPORTANT: * This persister is only used for uni-directional one-to-many mappings on a foreign key * (which are not yet supported). So currently this persister is not used. @@ -44,7 +44,7 @@ class OneToManyPersister extends AbstractCollectionPersister * @return string * @override */ - protected function _getDeleteRowSql(PersistentCollection $coll) + protected function _getDeleteRowSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); $targetClass = $this->_em->getClassMetadata($mapping->getTargetEntityName()); @@ -67,36 +67,36 @@ class OneToManyPersister extends AbstractCollectionPersister return array("UPDATE $table SET $setClause WHERE $whereClause", $this->_uow->getEntityIdentifier($element)); } - protected function _getInsertRowSql(PersistentCollection $coll) + protected function _getInsertRowSQL(PersistentCollection $coll) { return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz"; } /* Not used for OneToManyPersister */ - protected function _getUpdateRowSql(PersistentCollection $coll) + protected function _getUpdateRowSQL(PersistentCollection $coll) { return; } - + /** * Generates the SQL UPDATE that updates all the foreign keys to null. * * @param PersistentCollection $coll */ - protected function _getDeleteSql(PersistentCollection $coll) + protected function _getDeleteSQL(PersistentCollection $coll) { - + } - + /** * Gets the SQL parameters for the corresponding SQL statement to delete * the given collection. * * @param PersistentCollection $coll */ - protected function _getDeleteSqlParameters(PersistentCollection $coll) + protected function _getDeleteSQLParameters(PersistentCollection $coll) {} - + /** * Gets the SQL parameters for the corresponding SQL statement to insert the given * element of the given collection into the database. @@ -104,9 +104,9 @@ class OneToManyPersister extends AbstractCollectionPersister * @param PersistentCollection $coll * @param mixed $element */ - protected function _getInsertRowSqlParameters(PersistentCollection $coll, $element) + protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element) {} - + /** * Gets the SQL parameters for the corresponding SQL statement to delete the given * element from the given collection. @@ -114,6 +114,6 @@ class OneToManyPersister extends AbstractCollectionPersister * @param PersistentCollection $coll * @param mixed $element */ - protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element) + protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) {} } \ No newline at end of file From 561236bd5626d0ca99d81a12d9c80b66e54d96a1 Mon Sep 17 00:00:00 2001 From: "Roman S. Borschel" Date: Sat, 8 May 2010 14:08:18 +0200 Subject: [PATCH 5/8] [DDC-576] Fixed. --- lib/Doctrine/DBAL/Driver/Connection.php | 2 - .../DBAL/Driver/PDOMsSql/Connection.php | 29 +++++++----- lib/Doctrine/ORM/Id/IdentityGenerator.php | 31 ++++++++---- .../ORM/Id/SequenceIdentityGenerator.php | 46 ------------------ .../ORM/Mapping/ClassMetadataFactory.php | 24 ++++++---- .../ORM/Mapping/ClassMetadataInfo.php | 4 +- .../PostgreSQLIdentityStrategyTest.php | 47 +++++++++++++++++++ 7 files changed, 105 insertions(+), 78 deletions(-) delete mode 100644 lib/Doctrine/ORM/Id/SequenceIdentityGenerator.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index cee11f31a..4cc5776a6 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -1,7 +1,5 @@ exec('BEGIN TRANSACTION'); } + + /** + * {@inheritdoc} + */ + public function lastInsertId($name = null) + { + $stmt = $this->query('SELECT SCOPE_IDENTITY()'); + $id = $stmt->fetchColumn(); + $stmt->closeCursor(); + return $id; + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Id/IdentityGenerator.php b/lib/Doctrine/ORM/Id/IdentityGenerator.php index 96ad08add..75da2733d 100644 --- a/lib/Doctrine/ORM/Id/IdentityGenerator.php +++ b/lib/Doctrine/ORM/Id/IdentityGenerator.php @@ -21,23 +21,36 @@ namespace Doctrine\ORM\Id; use Doctrine\ORM\EntityManager; +/** + * Id generator that obtains IDs from special "identity" columns. These are columns + * that automatically get a database-generated, auto-incremented identifier on INSERT. + * This generator obtains the last insert id after such an insert. + */ class IdentityGenerator extends AbstractIdGenerator { + /** @var string The name of the sequence to pass to lastInsertId(), if any. */ + private $_seqName; + /** - * Generates an ID for the given entity. - * - * @param object $entity - * @return integer|float - * @override + * @param string $seqName The name of the sequence to pass to lastInsertId() + * to obtain the last generated identifier within the current + * database session/connection, if any. */ - public function generate(EntityManager $em, $entity) + public function __construct($seqName = null) { - return $em->getConnection()->lastInsertId(); + $this->_seqName = $seqName; } /** - * @return boolean - * @override + * {@inheritdoc} + */ + public function generate(EntityManager $em, $entity) + { + return $em->getConnection()->lastInsertId($this->_seqName); + } + + /** + * {@inheritdoc} */ public function isPostInsertGenerator() { diff --git a/lib/Doctrine/ORM/Id/SequenceIdentityGenerator.php b/lib/Doctrine/ORM/Id/SequenceIdentityGenerator.php deleted file mode 100644 index c7158bbed..000000000 --- a/lib/Doctrine/ORM/Id/SequenceIdentityGenerator.php +++ /dev/null @@ -1,46 +0,0 @@ -. - */ - -namespace Doctrine\ORM\Id; - -use Doctrine\ORM\EntityManager; - -class SequenceIdentityGenerator extends IdentityGenerator -{ - private $_sequenceName; - - public function __construct($sequenceName) - { - $this->_sequenceName = $sequenceName; - } - - public function generate(EntityManager $em, $entity) - { - return $em->getConnection()->lastInsertId($this->_sequenceName); - } - - /** - * @return boolean - * @override - */ - public function isPostInsertGenerator() - { - return true; - } -} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 1dc812cd7..fb3a09906 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -19,8 +19,10 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\ORM\ORMException, - Doctrine\DBAL\Platforms\AbstractPlatform, +use ReflectionException, + Doctrine\ORM\ORMException, + Doctrine\ORM\EntityManager, + Doctrine\DBAL\Platforms, Doctrine\ORM\Events; /** @@ -53,7 +55,7 @@ class ClassMetadataFactory * * @param $driver The metadata driver to use. */ - public function __construct(\Doctrine\ORM\EntityManager $em) + public function __construct(EntityManager $em) { $this->_em = $em; } @@ -94,15 +96,15 @@ class ClassMetadataFactory if ( ! $this->_initialized) { $this->_initialize(); } - + $metadata = array(); foreach ($this->_driver->getAllClassNames() as $className) { $metadata[] = $this->getMetadataFor($className); } - + return $metadata; } - + /** * Lazy initialization of this stuff, especially the metadata driver, * since these are not needed at all when a metadata cache is active. @@ -252,7 +254,7 @@ class ClassMetadataFactory // Invoke driver try { $this->_driver->loadMetadataForClass($className, $class); - } catch(\ReflectionException $e) { + } catch(ReflectionException $e) { throw MappingException::reflectionFailure($className, $e); } @@ -376,7 +378,13 @@ class ClassMetadataFactory // Create & assign an appropriate ID generator instance switch ($class->generatorType) { case ClassMetadata::GENERATOR_TYPE_IDENTITY: - $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator()); + // For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to + // __seq in PostgreSQL for SERIAL columns. + // Not pretty but necessary and the simplest solution that currently works. + $seqName = $this->_targetPlatform instanceof Platforms\PostgreSQLPlatform ? + $class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' : + null; + $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName)); break; case ClassMetadata::GENERATOR_TYPE_SEQUENCE: // If there is no sequence definition yet, create a default definition diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index a6100856c..b173e395d 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -317,7 +317,7 @@ class ClassMetadataInfo * READ-ONLY: The ID generator used for generating IDs for this class. * * @var AbstractIdGenerator - * @todo Remove + * @todo Remove! */ public $idGenerator; @@ -335,6 +335,7 @@ class ClassMetadataInfo * * * @var array + * @todo Merge with tableGeneratorDefinition into generic generatorDefinition */ public $sequenceGeneratorDefinition; @@ -343,6 +344,7 @@ class ClassMetadataInfo * TABLE generation strategy. * * @var array + * @todo Merge with tableGeneratorDefinition into generic generatorDefinition */ public $tableGeneratorDefinition; diff --git a/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php b/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php new file mode 100644 index 000000000..8b4a49ccf --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php @@ -0,0 +1,47 @@ +_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') { + $this->markTestSkipped('This test is special to the PostgreSQL IDENTITY key generation strategy.'); + } else { + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PostgreSQLIdentityEntity'), + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + } + + public function testPreSavePostSaveCallbacksAreInvoked() + { + $entity = new PostgreSQLIdentityEntity(); + $entity->setValue('hello'); + $this->_em->persist($entity); + $this->_em->flush(); + $this->assertTrue(is_numeric($entity->getId())); + $this->assertTrue($entity->getId() > 0); + $this->assertTrue($this->_em->contains($entity)); + } +} + +/** @Entity */ +class PostgreSQLIdentityEntity { + /** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") */ + private $id; + /** @Column(type="string") */ + private $value; + public function getId() {return $this->id;} + public function getValue() {return $this->value;} + public function setValue($value) {$this->value = $value;} +} From ee04b31da3dfaebebcf92c4df27db9d14353af89 Mon Sep 17 00:00:00 2001 From: "Roman S. Borschel" Date: Sat, 8 May 2010 14:20:44 +0200 Subject: [PATCH 6/8] Included new PostgreSQL IDENTITY/SERIAL test in functional suite. --- tests/Doctrine/Tests/ORM/Functional/AllTests.php | 1 + .../Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Functional/AllTests.php b/tests/Doctrine/Tests/ORM/Functional/AllTests.php index fa301beb9..c0827bcfb 100644 --- a/tests/Doctrine/Tests/ORM/Functional/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Functional/AllTests.php @@ -54,6 +54,7 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\ORM\Functional\EntityRepositoryTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\IdentityMapTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\DatabaseDriverTest'); + $suite->addTestSuite('Doctrine\Tests\ORM\Functional\PostgreSQLIdentityStrategyTest'); $suite->addTest(Locking\AllTests::suite()); $suite->addTest(SchemaTool\AllTests::suite()); diff --git a/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php b/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php index 8b4a49ccf..74b6ed213 100644 --- a/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php @@ -22,6 +22,12 @@ class PostgreSQLIdentityStrategyTest extends \Doctrine\Tests\OrmFunctionalTestCa } } } + + protected function tearDown() { + parent::tearDown(); + // drop sequence manually due to dependency + $this->_em->getConnection()->exec('DROP SEQUENCE postgresqlidentityentity_id_seq CASCADE'); + } public function testPreSavePostSaveCallbacksAreInvoked() { From dc3844e167b129a7d3987e6c1294c3e7607b27c6 Mon Sep 17 00:00:00 2001 From: Christian Heinrich Date: Sat, 8 May 2010 00:59:21 +0200 Subject: [PATCH 7/8] Fixed #DDC-571 --- lib/Doctrine/DBAL/Types/IntegerType.php | 6 +++--- tests/Doctrine/Tests/DBAL/Types/IntegerTest.php | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/Doctrine/DBAL/Types/IntegerType.php b/lib/Doctrine/DBAL/Types/IntegerType.php index abd946c51..c790ab130 100644 --- a/lib/Doctrine/DBAL/Types/IntegerType.php +++ b/lib/Doctrine/DBAL/Types/IntegerType.php @@ -25,7 +25,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; /** * Type that maps an SQL INT to a PHP integer. - * + * * @author Roman Borschel * @since 2.0 */ @@ -43,9 +43,9 @@ class IntegerType extends Type public function convertToPHPValue($value, AbstractPlatform $platform) { - return (int) $value; + return (null === $value) ? null : (int) $value; } - + public function getBindingType() { return \PDO::PARAM_INT; diff --git a/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php b/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php index 6d0efc5ed..f03e400ba 100644 --- a/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php @@ -6,7 +6,7 @@ use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DBAL\Mocks; require_once __DIR__ . '/../../TestInit.php'; - + class IntegerTest extends \Doctrine\Tests\DbalTestCase { protected @@ -19,10 +19,14 @@ class IntegerTest extends \Doctrine\Tests\DbalTestCase $this->_type = Type::getType('integer'); } - public function testDecimalConvertsToPHPValue() + public function testIntegerConvertsToPHPValue() { $this->assertTrue( is_integer($this->_type->convertToPHPValue('1', $this->_platform)) ); + + $this->assertTrue( + is_null($this->_type->convertToPHPValue(null, $this->_platform)) + ); } } \ No newline at end of file From 59d4e0c8e7744329cece96bd40ed4aa0e6773dd5 Mon Sep 17 00:00:00 2001 From: "Roman S. Borschel" Date: Sat, 8 May 2010 17:01:20 +0200 Subject: [PATCH 8/8] [DDC-481] Fixed. --- .../ORM/Mapping/ClassMetadataFactory.php | 4 ++-- .../ORM/Mapping/ClassMetadataInfo.php | 22 +++++++++++-------- .../ORM/Mapping/Driver/AnnotationDriver.php | 15 +++++-------- lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php | 2 -- lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 9 +++++--- .../ORM/Mapping/Driver/YamlDriver.php | 22 +++++++++---------- .../ORM/Mapping/ClassMetadataFactoryTest.php | 3 +++ 7 files changed, 39 insertions(+), 38 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index fb3a09906..6429989cd 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -277,9 +277,9 @@ class ClassMetadataFactory } else { $this->_completeIdGeneratorMapping($class); } - + if ($parent && $parent->isInheritanceTypeSingleTable()) { - $class->setTableName($parent->getTableName()); + $class->setPrimaryTable($parent->table); } $class->setParentClasses($visited); diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index b173e395d..8a016fd47 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -903,8 +903,8 @@ class ClassMetadataInfo /** * Sets the name of the primary table the class is mapped to. * - * @param string $tableName The table name. - * @deprecated + * @param string $tableName The table name. + * @deprecated Use {@link setPrimaryTable}. */ public function setTableName($tableName) { @@ -912,18 +912,22 @@ class ClassMetadataInfo } /** - * Sets the primary table definition. The provided array must have the + * Sets the primary table definition. The provided array supports the * following structure: * - * name => - * schema => - * catalog => + * name => (optional, defaults to class name) + * indexes => array of indexes (optional) + * uniqueConstraints => array of constraints (optional) * - * @param array $primaryTableDefinition + * @param array $table */ - public function setPrimaryTable(array $primaryTableDefinition) + public function setPrimaryTable(array $table) { - $this->table = $primaryTableDefinition; + if (isset($table['name']) && $table['name'][0] == '`') { + $table['name'] = trim($table['name'], '`'); + $table['quoted'] = true; + } + $this->table = $table; } /** diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index e44af01cf..6a61772a7 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -1,7 +1,5 @@ - * @author Guilherme Blanco - * @author Jonathan H. Wage - * @author Roman Borschel + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel */ class AnnotationDriver implements Driver { diff --git a/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php b/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php index 99b8a145a..ff86597f6 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php @@ -1,7 +1,5 @@ attributes + $table = array(); if (isset($xmlRoot['table'])) { - $metadata->table['name'] = (string)$xmlRoot['table']; + $table['name'] = (string)$xmlRoot['table']; } - + $metadata->setPrimaryTable($table); + + /* not implemented specially anyway. use table = schema.table if (isset($xmlRoot['schema'])) { $metadata->table['schema'] = (string)$xmlRoot['schema']; - } + }*/ if (isset($xmlRoot['inheritance-type'])) { $inheritanceType = (string)$xmlRoot['inheritance-type']; diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 873f9b21f..05a3fe125 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -1,7 +1,5 @@ - * @author Guilherme Blanco - * @author Jonathan H. Wage - * @author Roman Borschel + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel */ class YamlDriver extends AbstractFileDriver { @@ -61,13 +56,16 @@ class YamlDriver extends AbstractFileDriver } // Evaluate root level properties + $table = array(); if (isset($element['table'])) { - $metadata->table['name'] = $element['table']; + $table['name'] = $element['table']; } + $metadata->setPrimaryTable($table); + /* not implemented specially anyway. use table = schema.table if (isset($element['schema'])) { $metadata->table['schema'] = $element['schema']; - } + }*/ if (isset($element['inheritanceType'])) { $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType']))); diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index fcce4dff8..5236bdf91 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -26,6 +26,7 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase // Self-made metadata $cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1'); + $cm1->setPrimaryTable(array('name' => '`group`')); // Add a mapped field $cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar')); // Add a mapped field @@ -54,6 +55,8 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase // Go $cm1 = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity1'); + $this->assertEquals('group', $cm1->table['name']); + $this->assertTrue($cm1->table['quoted']); $this->assertEquals(array(), $cm1->parentClasses); $this->assertTrue($cm1->hasField('name')); $this->assertEquals(ClassMetadata::GENERATOR_TYPE_SEQUENCE, $cm1->generatorType);