diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 146dfb5c5..6c095c9e3 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -245,6 +245,9 @@ abstract class AbstractHydrator if (isset($cache[$key]['isMetaColumn'])) { if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) { $rowData[$dqlAlias][$cache[$key]['fieldName']] = $value; + if ($cache[$key]['isIdentifier']) { + $nonemptyComponents[$dqlAlias] = true; + } } continue; diff --git a/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php b/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php index 978a87601..f7d5031cd 100644 --- a/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php +++ b/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php @@ -19,7 +19,8 @@ namespace Doctrine\ORM\Mapping\Builder; -use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\ClassMetadataInfo; /** * Builder Object for ClassMetadata @@ -28,18 +29,19 @@ use Doctrine\ORM\Mapping\ClassMetadata; * @link www.doctrine-project.com * @since 2.2 * @author Benjamin Eberlei + * @author Guilherme Blanco */ class ClassMetadataBuilder { /** - * @var ClassMetadata + * @var \Doctrine\ORM\Mapping\ClassMetadataInfo */ private $cm; /** - * @param ClassMetadata $cm + * @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm */ - public function __construct(ClassMetadata $cm) + public function __construct(ClassMetadataInfo $cm) { $this->cm = $cm; } @@ -60,6 +62,7 @@ class ClassMetadataBuilder public function setMappedSuperClass() { $this->cm->isMappedSuperclass = true; + return $this; } @@ -72,6 +75,7 @@ class ClassMetadataBuilder public function setCustomRepositoryClass($repositoryClassName) { $this->cm->setCustomRepositoryClass($repositoryClassName); + return $this; } @@ -83,6 +87,7 @@ class ClassMetadataBuilder public function setReadOnly() { $this->cm->markReadOnly(); + return $this; } @@ -95,6 +100,7 @@ class ClassMetadataBuilder public function setTable($name) { $this->cm->setPrimaryTable(array('name' => $name)); + return $this; } @@ -110,7 +116,9 @@ class ClassMetadataBuilder if (!isset($this->cm->table['indexes'])) { $this->cm->table['indexes'] = array(); } + $this->cm->table['indexes'][$name] = array('columns' => $columns); + return $this; } @@ -123,10 +131,12 @@ class ClassMetadataBuilder */ public function addUniqueConstraint(array $columns, $name) { - if (!isset($this->cm->table['uniqueConstraints'])) { + if ( ! isset($this->cm->table['uniqueConstraints'])) { $this->cm->table['uniqueConstraints'] = array(); } + $this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns); + return $this; } @@ -143,6 +153,7 @@ class ClassMetadataBuilder 'name' => $name, 'query' => $dqlQuery, )); + return $this; } @@ -154,6 +165,7 @@ class ClassMetadataBuilder public function setJoinedTableInheritance() { $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED); + return $this; } @@ -165,6 +177,7 @@ class ClassMetadataBuilder public function setSingleTableInheritance() { $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); + return $this; } @@ -181,12 +194,13 @@ class ClassMetadataBuilder 'type' => $type, 'length' => $length, )); + return $this; } /** * Add a subclass to this inheritance hierachy. - * + * * @param string $name * @param string $class * @return ClassMetadataBuilder @@ -194,6 +208,7 @@ class ClassMetadataBuilder public function addDiscriminatorMapClass($name, $class) { $this->cm->addDiscriminatorMapClass($name, $class); + return $this; } @@ -205,6 +220,7 @@ class ClassMetadataBuilder public function setChangeTrackingPolicyDeferredExplicit() { $this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT); + return $this; } @@ -216,12 +232,13 @@ class ClassMetadataBuilder public function setChangeTrackingPolicyNotify() { $this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY); + return $this; } /** * Add lifecycle event - * + * * @param string $methodName * @param string $event * @return ClassMetadataBuilder @@ -229,6 +246,7 @@ class ClassMetadataBuilder public function addLifecycleEvent($methodName, $event) { $this->cm->addLifecycleCallback($methodName, $event); + return $this; } @@ -243,7 +261,9 @@ class ClassMetadataBuilder { $mapping['fieldName'] = $name; $mapping['type'] = $type; + $this->cm->mapField($mapping); + return $this; } @@ -256,12 +276,18 @@ class ClassMetadataBuilder */ public function createField($name, $type) { - return new FieldBuilder($this, array('fieldName' => $name, 'type' => $type)); + return new FieldBuilder( + $this, + array( + 'fieldName' => $name, + 'type' => $type + ) + ); } /** * Add a simple many to one association, optionally with the inversed by field. - * + * * @param string $name * @param string $targetEntity * @param string|null $inversedBy @@ -270,9 +296,11 @@ class ClassMetadataBuilder public function addManyToOne($name, $targetEntity, $inversedBy = null) { $builder = $this->createManyToOne($name, $targetEntity); + if ($inversedBy) { $builder->setInversedBy($inversedBy); } + return $builder->build(); } @@ -287,19 +315,33 @@ class ClassMetadataBuilder */ public function createManyToOne($name, $targetEntity) { - return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_ONE); + return new AssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::MANY_TO_ONE + ); } /** * Create OneToOne Assocation Builder - * + * * @param string $name * @param string $targetEntity * @return AssociationBuilder */ public function createOneToOne($name, $targetEntity) { - return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_ONE); + return new AssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::ONE_TO_ONE + ); } /** @@ -314,6 +356,7 @@ class ClassMetadataBuilder { $builder = $this->createOneToOne($name, $targetEntity); $builder->setMappedBy($mappedBy); + return $builder->build(); } @@ -328,9 +371,11 @@ class ClassMetadataBuilder public function addOwningOneToOne($name, $targetEntity, $inversedBy = null) { $builder = $this->createOneToOne($name, $targetEntity); + if ($inversedBy) { $builder->setInversedBy($inversedBy); } + return $builder->build(); } @@ -343,12 +388,19 @@ class ClassMetadataBuilder */ public function createManyToMany($name, $targetEntity) { - return new ManyToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_MANY); + return new ManyToManyAssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::MANY_TO_MANY + ); } /** * Add a simple owning many to many assocation. - * + * * @param string $name * @param string $targetEntity * @param string|null $inversedBy @@ -357,9 +409,11 @@ class ClassMetadataBuilder public function addOwningManyToMany($name, $targetEntity, $inversedBy = null) { $builder = $this->createManyToMany($name, $targetEntity); + if ($inversedBy) { $builder->setInversedBy($inversedBy); } + return $builder->build(); } @@ -375,24 +429,32 @@ class ClassMetadataBuilder { $builder = $this->createManyToMany($name, $targetEntity); $builder->setMappedBy($mappedBy); + return $builder->build(); } /** * Create a one to many assocation builder - * + * * @param string $name * @param string $targetEntity * @return OneToManyAssociationBuilder */ public function createOneToMany($name, $targetEntity) { - return new OneToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_MANY); + return new OneToManyAssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::ONE_TO_MANY + ); } /** * Add simple OneToMany assocation. - * + * * @param string $name * @param string $targetEntity * @param string $mappedBy @@ -402,6 +464,7 @@ class ClassMetadataBuilder { $builder = $this->createOneToMany($name, $targetEntity); $builder->setMappedBy($mappedBy); + return $builder->build(); } } diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php index 5c6305e25..3c292fda4 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMapping.php +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -120,7 +120,7 @@ class ResultSetMapping * results or joined entity results within this ResultSetMapping. * @param string $resultAlias The result alias with which the entity result should be * placed in the result structure. - * + * @return ResultSetMapping This ResultSetMapping instance. * @todo Rename: addRootEntity */ public function addEntityResult($class, $alias, $resultAlias = null) @@ -131,6 +131,8 @@ class ResultSetMapping if ($resultAlias !== null) { $this->isMixed = true; } + + return $this; } /** @@ -141,13 +143,15 @@ class ResultSetMapping * @param string $alias The alias of the entity result or joined entity result the discriminator * column should be used for. * @param string $discrColumn The name of the discriminator column in the SQL result set. - * + * @return ResultSetMapping This ResultSetMapping instance. * @todo Rename: addDiscriminatorColumn */ public function setDiscriminatorColumn($alias, $discrColumn) { $this->discriminatorColumns[$alias] = $discrColumn; $this->columnOwnerMap[$discrColumn] = $alias; + + return $this; } /** @@ -155,6 +159,7 @@ class ResultSetMapping * * @param string $alias The alias of an entity result or joined entity result. * @param string $fieldName The name of the field to use for indexing. + * @return ResultSetMapping This ResultSetMapping instance. */ public function addIndexBy($alias, $fieldName) { @@ -180,17 +185,21 @@ class ResultSetMapping throw new \LogicException($message); } */ + + return $this; } /** * Set to index by a scalar result column name * * @param $resultColumnName - * @return void + * @return ResultSetMapping This ResultSetMapping instance. */ public function addIndexByScalar($resultColumnName) { $this->indexByMap['scalars'] = $resultColumnName; + + return $this; } /** @@ -198,11 +207,13 @@ class ResultSetMapping * * @param $alias * @param $resultColumnName - * @return void + * @return ResultSetMapping This ResultSetMapping instance. */ public function addIndexByColumn($alias, $resultColumnName) { $this->indexByMap[$alias] = $resultColumnName; + + return $this; } /** @@ -242,6 +253,7 @@ class ResultSetMapping * the field $fieldName is defined on a subclass, specify that here. * If not specified, the field is assumed to belong to the class * designated by $alias. + * @return ResultSetMapping This ResultSetMapping instance. * @todo Rename: addField */ public function addFieldResult($alias, $columnName, $fieldName, $declaringClass = null) @@ -256,6 +268,8 @@ class ResultSetMapping if ( ! $this->isMixed && $this->scalarMappings) { $this->isMixed = true; } + + return $this; } /** @@ -265,6 +279,7 @@ class ResultSetMapping * @param string $alias The unique alias to use for the joined entity. * @param string $parentAlias The alias of the entity result that is the parent of this joined result. * @param object $relation The association field that connects the parent entity result with the joined entity result. + * @return ResultSetMapping This ResultSetMapping instance. * @todo Rename: addJoinedEntity */ public function addJoinedEntityResult($class, $alias, $parentAlias, $relation) @@ -272,6 +287,8 @@ class ResultSetMapping $this->aliasMap[$alias] = $class; $this->parentAliasMap[$alias] = $parentAlias; $this->relationMap[$alias] = $relation; + + return $this; } /** @@ -279,6 +296,7 @@ class ResultSetMapping * * @param string $columnName The name of the column in the SQL result set. * @param string $alias The result alias with which the scalar result should be placed in the result structure. + * @return ResultSetMapping This ResultSetMapping instance. * @todo Rename: addScalar */ public function addScalarResult($columnName, $alias) @@ -288,6 +306,8 @@ class ResultSetMapping if ( ! $this->isMixed && $this->fieldMappings) { $this->isMixed = true; } + + return $this; } /** @@ -439,6 +459,7 @@ class ResultSetMapping * @param string $columnName * @param string $fieldName * @param bool + * @return ResultSetMapping This ResultSetMapping instance. */ public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn = false) { @@ -448,5 +469,7 @@ class ResultSetMapping if ($isIdentifierColumn) { $this->isIdentifierColumn[$alias][$columnName] = true; } + + return $this; } } diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 803e6683c..eb3111fb8 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -1735,7 +1735,7 @@ class UnitOfWork implements PropertyChangedListener $managedCol->initialize(); // clear and set dirty a managed collection if its not also the same collection to merge from. - if (!$managedCol->isEmpty() && $managedCol != $mergeCol) { + if (!$managedCol->isEmpty() && $managedCol !== $mergeCol) { $managedCol->unwrap()->clear(); $managedCol->setDirty(true); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php index 1639f98bd..2523b5b72 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php @@ -59,12 +59,7 @@ class DDC1400Test extends \Doctrine\Tests\OrmFunctionalTestCase $q->setParameter('activeUser', $user1); $articles = $q->getResult(); - var_dump(array_keys($articles[0]->userStates->toArray())); - $this->_em->flush(); - var_dump($this->_sqlLoggerStack); - - } } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php new file mode 100644 index 000000000..9bd3360b8 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php @@ -0,0 +1,64 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1515Foo'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1515Bar'), + )); + } + + public function testIssue() + { + $bar = new DDC1515Bar(); + $this->_em->persist($bar); + $this->_em->flush(); + + $foo = new DDC1515Foo(); + $foo->bar = $bar; + $this->_em->persist($foo); + $this->_em->flush(); + $this->_em->clear(); + + $bar = $this->_em->find(__NAMESPACE__ . '\DDC1515Bar', $bar->id); + $this->assertInstanceOf(__NAMESPACE__.'\DDC1515Foo', $bar->foo); + } +} + +/** + * @Entity + */ +class DDC1515Foo +{ + /** + * @OneToOne(targetEntity="DDC1515Bar", inversedBy="foo") @Id + */ + public $bar; +} + +/** + * @Entity + */ +class DDC1515Bar +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1515Foo", mappedBy="bar") + */ + public $foo; +} + + diff --git a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php index 562fd4d87..d18c4dbb7 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php @@ -14,7 +14,14 @@ require_once __DIR__ . '/../../TestInit.php'; */ class ResultSetMappingTest extends \Doctrine\Tests\OrmTestCase { + /** + * @var ResultSetMapping + */ private $_rsm; + + /** + * @var \Doctrine\ORM\EntityManager + */ private $_em; protected function setUp() { @@ -56,5 +63,35 @@ class ResultSetMappingTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals('username', $this->_rsm->getFieldName('username')); $this->assertEquals('name', $this->_rsm->getFieldName('name')); } + + /** + * @group DDC-1057 + * + * Fluent interface test, not a real result set mapping + */ + public function testFluentInterface() + { + $rms = $this->_rsm; + + $rms->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser','u') + ->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber','p','u','phonenumbers') + ->addFieldResult('u', 'id', 'id') + ->addFieldResult('u', 'name', 'name') + ->setDiscriminatorColumn('name', 'name') + ->addIndexByColumn('id', 'id') + ->addIndexBy('username', 'username') + ->addIndexByScalar('sclr0') + ->addScalarResult('sclr0', 'numPhones') + ->addMetaResult('a', 'user_id', 'user_id'); + + + $this->assertTrue($rms->hasIndexBy('id')); + $this->assertTrue($rms->isFieldResult('id')); + $this->assertTrue($rms->isFieldResult('name')); + $this->assertTrue($rms->isScalarResult('sclr0')); + $this->assertTrue($rms->isRelation('p')); + $this->assertTrue($rms->hasParentAlias('p')); + $this->assertTrue($rms->isMixedResult()); + } }