Commit 53eb51b6 authored by romanb's avatar romanb

[2.0][DDC-422] Fixed.

parent 9bb25925
......@@ -371,70 +371,7 @@ class UnitOfWork implements PropertyChangedListener
}
/**
* Method can be used to compute the change-set of any entity.
*
* @Internal
*
* @Todo inline _computeEntityChanges to here?
*
* @param ClassMetadata $class
* @param object $entity
* @return void
*/
public function computeChangeSet($class, $entity)
{
$this->_computeEntityChanges($class, $entity);
// Look for changes in associations of the entity
foreach ($class->associationMappings as $assoc) {
$val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
if ($val !== null) {
$this->_computeAssociationChanges($assoc, $val);
}
}
}
/**
* Computes all the changes that have been done to entities and collections
* since the last commit and stores these changes in the _entityChangeSet map
* temporarily for access by the persisters, until the UoW commit is finished.
*/
public function computeChangeSets()
{
// Compute changes for INSERTed entities first. This must always happen.
foreach ($this->_entityInsertions as $entity) {
$class = $this->_em->getClassMetadata(get_class($entity));
$this->computeChangeSet($class, $entity);
}
// Compute changes for other MANAGED entities. Change tracking policies take effect here.
foreach ($this->_identityMap as $className => $entities) {
$class = $this->_em->getClassMetadata($className);
// Skip class if change tracking happens through notification
if ($class->isChangeTrackingNotify() /* || $class->isReadOnly*/) {
continue;
}
// If change tracking is explicit, then only compute changes on explicitly saved entities
$entitiesToProcess = $class->isChangeTrackingDeferredExplicit() ?
$this->_scheduledForDirtyCheck[$className] : $entities;
foreach ($entitiesToProcess as $entity) {
// Ignore uninitialized proxy objects
if (/* $entity is readOnly || */ $entity instanceof Proxy && ! $entity->__isInitialized__) {
continue;
}
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
$oid = spl_object_hash($entity);
if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) {
$this->computeChangeSet($class, $entity);
}
}
}
}
/**
* Computes the changes done to a single entity.
* Computes the changes that happened to a single entity.
*
* Modifies/populates the following properties:
*
......@@ -461,14 +398,14 @@ class UnitOfWork implements PropertyChangedListener
* @param ClassMetadata $class The class descriptor of the entity.
* @param object $entity The entity for which to compute the changes.
*/
private function _computeEntityChanges($class, $entity)
public function computeChangeSet(Mapping\ClassMetadata $class, $entity)
{
$oid = spl_object_hash($entity);
if ( ! $class->isInheritanceTypeNone()) {
$class = $this->_em->getClassMetadata(get_class($entity));
}
$oid = spl_object_hash($entity);
$actualData = array();
foreach ($class->reflFields as $name => $refProp) {
if ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) {
......@@ -550,6 +487,54 @@ class UnitOfWork implements PropertyChangedListener
}
}
}
// Look for changes in associations of the entity
foreach ($class->associationMappings as $assoc) {
$val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
if ($val !== null) {
$this->_computeAssociationChanges($assoc, $val);
}
}
}
/**
* Computes all the changes that have been done to entities and collections
* since the last commit and stores these changes in the _entityChangeSet map
* temporarily for access by the persisters, until the UoW commit is finished.
*/
public function computeChangeSets()
{
// Compute changes for INSERTed entities first. This must always happen.
foreach ($this->_entityInsertions as $entity) {
$class = $this->_em->getClassMetadata(get_class($entity));
$this->computeChangeSet($class, $entity);
}
// Compute changes for other MANAGED entities. Change tracking policies take effect here.
foreach ($this->_identityMap as $className => $entities) {
$class = $this->_em->getClassMetadata($className);
// Skip class if change tracking happens through notification
if ($class->isChangeTrackingNotify() /* || $class->isReadOnly*/) {
continue;
}
// If change tracking is explicit, then only compute changes on explicitly saved entities
$entitiesToProcess = $class->isChangeTrackingDeferredExplicit() ?
$this->_scheduledForDirtyCheck[$className] : $entities;
foreach ($entitiesToProcess as $entity) {
// Ignore uninitialized proxy objects
if (/* $entity is readOnly || */ $entity instanceof Proxy && ! $entity->__isInitialized__) {
continue;
}
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
$oid = spl_object_hash($entity);
if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) {
$this->computeChangeSet($class, $entity);
}
}
}
}
/**
......
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
class DDC422Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSqlLogger(new \Doctrine\DBAL\Logging\EchoSqlLogger);
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Guest'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Customer'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Contact')
));
}
/**
* @group DDC-422
*/
public function testIssue()
{
$customer = new DDC422Customer;
$this->_em->persist($customer);
$this->_em->flush();
$this->_em->clear();
$customer = $this->_em->find(get_class($customer), $customer->id);
$this->assertTrue($customer->contacts instanceof \Doctrine\ORM\PersistentCollection);
$this->assertFalse($customer->contacts->isInitialized());
$contact = new DDC422Contact;
$customer->contacts->add($contact);
$this->assertTrue($customer->contacts->isDirty());
$this->assertFalse($customer->contacts->isInitialized());
$this->_em->flush();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from ddc422_customers_contacts"));
}
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"guest" = "DDC422Guest", "customer" = "DDC422Customer"})
*/
class DDC422Guest {
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/** @Entity */
class DDC422Customer extends DDC422Guest {
/**
* @ManyToMany(targetEntity="DDC422Contact", cascade={"persist","remove"})
* @JoinTable(name="ddc422_customers_contacts",
* joinColumns={@JoinColumn(name="customer_id", referencedColumnName="id", onDelete="cascade" )},
* inverseJoinColumns={@JoinColumn(name="contact_id", referencedColumnName="id", onDelete="cascade" )}
* )
*/
public $contacts;
public function __construct() {
$this->contacts = new \Doctrine\Common\Collections\ArrayCollection;
}
}
/** @Entity */
class DDC422Contact {
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment