Fix one to one inverse side cached entity association key generation
This commit is contained in:
parent
3a44a3dada
commit
e64f44ec9b
@ -82,16 +82,31 @@ class DefaultEntityHydrator implements EntityHydrator
|
|||||||
|
|
||||||
if ( ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
if ( ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||||
unset($data[$name]);
|
unset($data[$name]);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! isset($assoc['cache'])) {
|
if ( ! isset($assoc['cache'])) {
|
||||||
$targetClassMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
|
$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]);
|
unset($data[$name]);
|
||||||
|
|
||||||
foreach ($associationIds as $fieldName => $fieldValue) {
|
foreach ($associationIds as $fieldName => $fieldValue) {
|
||||||
if (isset($targetClassMetadata->associationMappings[$fieldName])){
|
if (isset($targetClassMetadata->fieldMappings[$fieldName])) {
|
||||||
|
$fieldMapping = $targetClassMetadata->fieldMappings[$fieldName];
|
||||||
|
|
||||||
|
$data[$owningAssociation['targetToSourceKeyColumns'][$fieldMapping['columnName']]] = $fieldValue;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
|
$targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
|
||||||
|
|
||||||
foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
|
foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
|
||||||
@ -99,9 +114,6 @@ class DefaultEntityHydrator implements EntityHydrator
|
|||||||
$data[$localColumn] = $fieldValue;
|
$data[$localColumn] = $fieldValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$data[$assoc['targetToSourceKeyColumns'][$targetClassMetadata->fieldMappings[$fieldName]['columnName']]] = $fieldValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
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;
|
namespace Doctrine\Tests\ORM\Functional;
|
||||||
|
|
||||||
|
use Doctrine\Tests\Models\Cache\Address;
|
||||||
|
use Doctrine\Tests\Models\Cache\Person;
|
||||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||||
|
|
||||||
use Doctrine\Tests\Models\Cache\Country;
|
use Doctrine\Tests\Models\Cache\Country;
|
||||||
@ -25,6 +27,8 @@ use Doctrine\Tests\Models\Cache\AttractionLocationInfo;
|
|||||||
*/
|
*/
|
||||||
abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
|
abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
|
||||||
{
|
{
|
||||||
|
protected $people = array();
|
||||||
|
protected $addresses = array();
|
||||||
protected $countries = array();
|
protected $countries = array();
|
||||||
protected $states = array();
|
protected $states = array();
|
||||||
protected $cities = array();
|
protected $cities = array();
|
||||||
@ -224,6 +228,37 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
|
|||||||
$this->_em->flush();
|
$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)
|
protected function getEntityRegion($className)
|
||||||
{
|
{
|
||||||
return $this->cache->getEntityCacheRegion($className)->getName();
|
return $this->cache->getEntityCacheRegion($className)->getName();
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
namespace Doctrine\Tests\ORM\Functional;
|
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\Client;
|
||||||
|
use Doctrine\Tests\Models\Cache\ComplexAction;
|
||||||
|
use Doctrine\Tests\Models\Cache\Person;
|
||||||
use Doctrine\Tests\Models\Cache\Token;
|
use Doctrine\Tests\Models\Cache\Token;
|
||||||
use Doctrine\Tests\Models\Cache\Traveler;
|
use Doctrine\Tests\Models\Cache\Traveler;
|
||||||
use Doctrine\Tests\Models\Cache\TravelerProfile;
|
use Doctrine\Tests\Models\Cache\TravelerProfile;
|
||||||
@ -189,6 +193,67 @@ class SecondLevelCacheOneToOneTest extends SecondLevelCacheAbstractTest
|
|||||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount());
|
$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()
|
public function testPutAndLoadNonCacheableOneToOne()
|
||||||
{
|
{
|
||||||
$this->assertNull($this->cache->getEntityCacheRegion(Client::CLASSNAME));
|
$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\Token',
|
||||||
'Doctrine\Tests\Models\Cache\Login',
|
'Doctrine\Tests\Models\Cache\Login',
|
||||||
'Doctrine\Tests\Models\Cache\Client',
|
'Doctrine\Tests\Models\Cache\Client',
|
||||||
|
'Doctrine\Tests\Models\Cache\Person',
|
||||||
|
'Doctrine\Tests\Models\Cache\Address',
|
||||||
'Doctrine\Tests\Models\Cache\Action',
|
'Doctrine\Tests\Models\Cache\Action',
|
||||||
'Doctrine\Tests\Models\Cache\ComplexAction',
|
'Doctrine\Tests\Models\Cache\ComplexAction',
|
||||||
'Doctrine\Tests\Models\Cache\AttractionInfo',
|
'Doctrine\Tests\Models\Cache\AttractionInfo',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user