1
0
mirror of synced 2025-02-02 21:41:45 +03:00

Fix one to one inverse side cached entity association key generation

This commit is contained in:
Guilherme Blanco 2015-11-13 06:02:18 +00:00
parent 3a44a3dada
commit e64f44ec9b
6 changed files with 194 additions and 10 deletions

View File

@ -80,27 +80,39 @@ class DefaultEntityHydrator implements EntityHydrator
continue;
}
if (! ($assoc['type'] & ClassMetadata::TO_ONE)) {
if ( ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
unset($data[$name]);
continue;
}
if ( ! isset($assoc['cache'])) {
$targetClassMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
$associationIds = $this->identifierFlattener->flattenIdentifier($targetClassMetadata, $targetClassMetadata->getIdentifierValues($data[$name]));
$owningAssociation = ( ! $assoc['isOwningSide'])
? $targetClassMetadata->associationMappings[$assoc['mappedBy']]
: $assoc;
$associationIds = $this->identifierFlattener->flattenIdentifier(
$targetClassMetadata,
$targetClassMetadata->getIdentifierValues($data[$name])
);
unset($data[$name]);
foreach ($associationIds as $fieldName => $fieldValue) {
if (isset($targetClassMetadata->associationMappings[$fieldName])){
$targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
if (isset($targetClassMetadata->fieldMappings[$fieldName])) {
$fieldMapping = $targetClassMetadata->fieldMappings[$fieldName];
foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
if (isset($targetAssoc['sourceToTargetKeyColumns'][$referencedColumn])) {
$data[$localColumn] = $fieldValue;
}
$data[$owningAssociation['targetToSourceKeyColumns'][$fieldMapping['columnName']]] = $fieldValue;
continue;
}
$targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
if (isset($targetAssoc['sourceToTargetKeyColumns'][$referencedColumn])) {
$data[$localColumn] = $fieldValue;
}
} else {
$data[$assoc['targetToSourceKeyColumns'][$targetClassMetadata->fieldMappings[$fieldName]['columnName']]] = $fieldValue;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Doctrine\Tests\Models\Cache;
/**
* @Entity
* @Table("cache_client_address")
*/
class Address
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
public $id;
/**
* @JoinColumn(name="person_id", referencedColumnName="id")
* @OneToOne(targetEntity="Person", inversedBy="address")
*/
public $person;
/**
* @Column
*/
public $location;
public function __construct($location)
{
$this->location = $location;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Doctrine\Tests\Models\Cache;
/**
* @Entity
* @Table("cache_person")
* @Cache("NONSTRICT_READ_WRITE")
*/
class Person
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
public $id;
/**
* @Column(unique=true)
*/
public $name;
/**
* @OneToOne(targetEntity="Address", mappedBy="person")
*/
public $address;
public function __construct($name)
{
$this->name = $name;
}
}

View File

@ -2,6 +2,8 @@
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\Cache\Address;
use Doctrine\Tests\Models\Cache\Person;
use Doctrine\Tests\OrmFunctionalTestCase;
use Doctrine\Tests\Models\Cache\Country;
@ -25,6 +27,8 @@ use Doctrine\Tests\Models\Cache\AttractionLocationInfo;
*/
abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
{
protected $people = array();
protected $addresses = array();
protected $countries = array();
protected $states = array();
protected $cities = array();
@ -224,6 +228,37 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
$this->_em->flush();
}
protected function loadFixturesPersonWithAddress()
{
$person1 = new Person('Guilherme Blanco');
$address1 = new Address('Canada');
$person1->address = $address1;
$address1->person = $person1;
$person2 = new Person('Marco Pivetta');
$address2 = new Address('Germany');
$person2->address = $address2;
$address2->person = $person2;
$this->people[] = $person1;
$this->people[] = $person2;
$this->addresses[] = $address1;
$this->addresses[] = $address2;
foreach ($this->people as $person) {
$this->_em->persist($person);
}
foreach ($this->addresses as $address) {
$this->_em->persist($address);
}
$this->_em->flush();
}
protected function getEntityRegion($className)
{
return $this->cache->getEntityCacheRegion($className)->getName();

View File

@ -2,7 +2,11 @@
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\Cache\Action;
use Doctrine\Tests\Models\Cache\Address;
use Doctrine\Tests\Models\Cache\Client;
use Doctrine\Tests\Models\Cache\ComplexAction;
use Doctrine\Tests\Models\Cache\Person;
use Doctrine\Tests\Models\Cache\Token;
use Doctrine\Tests\Models\Cache\Traveler;
use Doctrine\Tests\Models\Cache\TravelerProfile;
@ -189,6 +193,67 @@ class SecondLevelCacheOneToOneTest extends SecondLevelCacheAbstractTest
$this->assertEquals($queryCount, $this->getCurrentQueryCount());
}
public function testInverseSidePutAndLoadOneToOneBidirectionalRelation()
{
$this->loadFixturesPersonWithAddress();
$this->_em->clear();
$this->cache->evictEntityRegion(Person::CLASSNAME);
$this->cache->evictEntityRegion(Address::CLASSNAME);
$entity1 = $this->addresses[0]->person;
$entity2 = $this->addresses[1]->person;
$this->assertFalse($this->cache->containsEntity(Person::CLASSNAME, $entity1->id));
$this->assertFalse($this->cache->containsEntity(Person::CLASSNAME, $entity2->id));
$this->assertFalse($this->cache->containsEntity(Address::CLASSNAME, $entity1->address->id));
$this->assertFalse($this->cache->containsEntity(Address::CLASSNAME, $entity2->address->id));
$p1 = $this->_em->find(Person::CLASSNAME, $entity1->id);
$p2 = $this->_em->find(Person::CLASSNAME, $entity2->id);
$this->assertEquals($entity1->id, $p1->id);
$this->assertEquals($entity1->name, $p1->name);
$this->assertEquals($entity1->address->id, $p1->address->id);
$this->assertEquals($entity1->address->location, $p1->address->location);
$this->assertEquals($entity2->id, $p2->id);
$this->assertEquals($entity2->name, $p2->name);
$this->assertEquals($entity2->address->id, $p2->address->id);
$this->assertEquals($entity2->address->location, $p2->address->location);
$this->assertTrue($this->cache->containsEntity(Person::CLASSNAME, $entity1->id));
$this->assertTrue($this->cache->containsEntity(Person::CLASSNAME, $entity2->id));
// The inverse side its not cached
$this->assertFalse($this->cache->containsEntity(Address::CLASSNAME, $entity1->address->id));
$this->assertFalse($this->cache->containsEntity(Address::CLASSNAME, $entity2->address->id));
$this->_em->clear();
$queryCount = $this->getCurrentQueryCount();
$p3 = $this->_em->find(Person::CLASSNAME, $entity1->id);
$p4 = $this->_em->find(Person::CLASSNAME, $entity2->id);
$this->assertInstanceOf(Person::CLASSNAME, $p3);
$this->assertInstanceOf(Person::CLASSNAME, $p4);
$this->assertInstanceOf(Address::CLASSNAME, $p3->address);
$this->assertInstanceOf(Address::CLASSNAME, $p4->address);
$this->assertEquals($entity1->id, $p3->id);
$this->assertEquals($entity1->name, $p3->name);
$this->assertEquals($entity1->address->id, $p3->address->id);
$this->assertEquals($entity1->address->location, $p3->address->location);
$this->assertEquals($entity2->id, $p4->id);
$this->assertEquals($entity2->name, $p4->name);
$this->assertEquals($entity2->address->id, $p4->address->id);
$this->assertEquals($entity2->address->location, $p4->address->location);
$this->assertEquals($queryCount + 2, $this->getCurrentQueryCount());
}
public function testPutAndLoadNonCacheableOneToOne()
{
$this->assertNull($this->cache->getEntityCacheRegion(Client::CLASSNAME));

View File

@ -189,6 +189,8 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
'Doctrine\Tests\Models\Cache\Token',
'Doctrine\Tests\Models\Cache\Login',
'Doctrine\Tests\Models\Cache\Client',
'Doctrine\Tests\Models\Cache\Person',
'Doctrine\Tests\Models\Cache\Address',
'Doctrine\Tests\Models\Cache\Action',
'Doctrine\Tests\Models\Cache\ComplexAction',
'Doctrine\Tests\Models\Cache\AttractionInfo',