Fix one to one inverse side cached entity association key generation
This commit is contained in:
parent
3a44a3dada
commit
e64f44ec9b
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
35
tests/Doctrine/Tests/Models/Cache/Address.php
Normal file
35
tests/Doctrine/Tests/Models/Cache/Address.php
Normal 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;
|
||||
}
|
||||
}
|
35
tests/Doctrine/Tests/Models/Cache/Person.php
Normal file
35
tests/Doctrine/Tests/Models/Cache/Person.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user