2008-06-16 18:31:21 +00:00
|
|
|
<?php
|
2009-01-04 16:15:32 +00:00
|
|
|
|
2009-01-22 19:38:10 +00:00
|
|
|
namespace Doctrine\Tests\ORM;
|
2009-01-04 16:15:32 +00:00
|
|
|
|
2015-01-18 00:37:21 +01:00
|
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
|
|
use Doctrine\Common\NotifyPropertyChanged;
|
|
|
|
use Doctrine\Common\PropertyChangedListener;
|
|
|
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
2016-07-07 19:58:43 +02:00
|
|
|
use Doctrine\ORM\ORMInvalidArgumentException;
|
2010-07-04 18:55:49 +02:00
|
|
|
use Doctrine\ORM\UnitOfWork;
|
2009-01-22 19:38:10 +00:00
|
|
|
use Doctrine\Tests\Mocks\ConnectionMock;
|
2015-01-18 00:37:21 +01:00
|
|
|
use Doctrine\Tests\Mocks\DriverMock;
|
2009-01-22 19:38:10 +00:00
|
|
|
use Doctrine\Tests\Mocks\EntityManagerMock;
|
|
|
|
use Doctrine\Tests\Mocks\EntityPersisterMock;
|
2015-01-18 00:37:21 +01:00
|
|
|
use Doctrine\Tests\Mocks\UnitOfWorkMock;
|
2016-05-11 01:55:12 +07:00
|
|
|
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
2009-01-22 19:38:10 +00:00
|
|
|
use Doctrine\Tests\Models\Forum\ForumAvatar;
|
2015-01-18 00:37:21 +01:00
|
|
|
use Doctrine\Tests\Models\Forum\ForumUser;
|
2016-06-06 00:08:26 +02:00
|
|
|
use Doctrine\Tests\Models\GeoNames\City;
|
|
|
|
use Doctrine\Tests\Models\GeoNames\Country;
|
2016-05-11 01:55:12 +07:00
|
|
|
use Doctrine\Tests\OrmTestCase;
|
2015-01-18 00:37:21 +01:00
|
|
|
use stdClass;
|
2009-01-22 19:38:10 +00:00
|
|
|
|
2008-07-20 20:13:24 +00:00
|
|
|
/**
|
|
|
|
* UnitOfWork tests.
|
|
|
|
*/
|
2016-05-11 01:55:12 +07:00
|
|
|
class UnitOfWorkTest extends OrmTestCase
|
2008-06-16 18:31:21 +00:00
|
|
|
{
|
2015-01-18 00:37:21 +01:00
|
|
|
/**
|
|
|
|
* SUT
|
|
|
|
*
|
|
|
|
* @var UnitOfWorkMock
|
|
|
|
*/
|
2008-06-16 18:31:21 +00:00
|
|
|
private $_unitOfWork;
|
2015-01-18 00:37:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides a sequence mock to the UnitOfWork
|
|
|
|
*
|
|
|
|
* @var ConnectionMock
|
|
|
|
*/
|
2008-07-20 20:13:24 +00:00
|
|
|
private $_connectionMock;
|
2015-01-18 00:37:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The EntityManager mock that provides the mock persisters
|
|
|
|
*
|
|
|
|
* @var EntityManagerMock
|
|
|
|
*/
|
2008-07-20 20:13:24 +00:00
|
|
|
private $_emMock;
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2008-06-16 18:31:21 +00:00
|
|
|
protected function setUp() {
|
|
|
|
parent::setUp();
|
2015-01-18 00:37:21 +01:00
|
|
|
$this->_connectionMock = new ConnectionMock(array(), new DriverMock());
|
2009-02-17 11:02:11 +00:00
|
|
|
$this->_emMock = EntityManagerMock::create($this->_connectionMock);
|
2008-09-07 13:48:40 +00:00
|
|
|
// SUT
|
2009-01-22 19:38:10 +00:00
|
|
|
$this->_unitOfWork = new UnitOfWorkMock($this->_emMock);
|
2009-01-03 19:50:13 +00:00
|
|
|
$this->_emMock->setUnitOfWork($this->_unitOfWork);
|
2008-06-16 18:31:21 +00:00
|
|
|
}
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2008-06-16 18:31:21 +00:00
|
|
|
protected function tearDown() {
|
|
|
|
}
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2008-07-20 20:13:24 +00:00
|
|
|
public function testRegisterRemovedOnNewEntityIsIgnored()
|
2008-06-16 18:31:21 +00:00
|
|
|
{
|
2009-01-03 19:50:13 +00:00
|
|
|
$user = new ForumUser();
|
|
|
|
$user->username = 'romanb';
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertFalse($this->_unitOfWork->isScheduledForDelete($user));
|
|
|
|
$this->_unitOfWork->scheduleForDelete($user);
|
2011-12-19 22:56:19 +01:00
|
|
|
$this->assertFalse($this->_unitOfWork->isScheduledForDelete($user));
|
2008-06-16 18:31:21 +00:00
|
|
|
}
|
2011-12-19 22:56:19 +01:00
|
|
|
|
|
|
|
|
2008-07-20 20:13:24 +00:00
|
|
|
/* Operational tests */
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2008-07-20 20:13:24 +00:00
|
|
|
public function testSavingSingleEntityWithIdentityColumnForcesInsert()
|
2009-01-03 19:50:13 +00:00
|
|
|
{
|
|
|
|
// Setup fake persister and id generator for identity generation
|
2015-01-18 00:37:21 +01:00
|
|
|
$userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser'));
|
2009-02-02 11:55:50 +00:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
|
2015-01-18 00:37:21 +01:00
|
|
|
$userPersister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
2009-01-03 19:50:13 +00:00
|
|
|
|
|
|
|
// Test
|
|
|
|
$user = new ForumUser();
|
|
|
|
$user->username = 'romanb';
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->persist($user);
|
2009-01-03 19:50:13 +00:00
|
|
|
|
|
|
|
// Check
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertEquals(0, count($userPersister->getInserts()));
|
2009-01-03 19:50:13 +00:00
|
|
|
$this->assertEquals(0, count($userPersister->getUpdates()));
|
2011-12-19 22:56:19 +01:00
|
|
|
$this->assertEquals(0, count($userPersister->getDeletes()));
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertFalse($this->_unitOfWork->isInIdentityMap($user));
|
2008-07-20 20:13:24 +00:00
|
|
|
// should no longer be scheduled for insert
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertTrue($this->_unitOfWork->isScheduledForInsert($user));
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2008-08-01 18:46:14 +00:00
|
|
|
// Now lets check whether a subsequent commit() does anything
|
2009-01-03 19:50:13 +00:00
|
|
|
$userPersister->reset();
|
|
|
|
|
|
|
|
// Test
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->commit();
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
// Check.
|
|
|
|
$this->assertEquals(1, count($userPersister->getInserts()));
|
2009-01-03 19:50:13 +00:00
|
|
|
$this->assertEquals(0, count($userPersister->getUpdates()));
|
|
|
|
$this->assertEquals(0, count($userPersister->getDeletes()));
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
// should have an id
|
|
|
|
$this->assertTrue(is_numeric($user->id));
|
2008-07-20 20:13:24 +00:00
|
|
|
}
|
2009-01-03 19:50:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests a scenario where a save() operation is cascaded from a ForumUser
|
|
|
|
* to its associated ForumAvatar, both entities using IDENTITY id generation.
|
|
|
|
*/
|
|
|
|
public function testCascadedIdentityColumnInsert()
|
2008-08-22 09:05:14 +00:00
|
|
|
{
|
2009-01-03 19:50:13 +00:00
|
|
|
// Setup fake persister and id generator for identity generation
|
|
|
|
//ForumUser
|
2015-01-18 00:37:21 +01:00
|
|
|
$userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser'));
|
2009-02-02 11:55:50 +00:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
|
2015-01-18 00:37:21 +01:00
|
|
|
$userPersister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
2009-01-03 19:50:13 +00:00
|
|
|
// ForumAvatar
|
2015-01-18 00:37:21 +01:00
|
|
|
$avatarPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumAvatar'));
|
2009-02-02 11:55:50 +00:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister);
|
2015-01-18 00:37:21 +01:00
|
|
|
$avatarPersister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
2009-01-03 19:50:13 +00:00
|
|
|
|
|
|
|
// Test
|
|
|
|
$user = new ForumUser();
|
|
|
|
$user->username = 'romanb';
|
2008-08-22 09:05:14 +00:00
|
|
|
$avatar = new ForumAvatar();
|
2009-01-03 19:50:13 +00:00
|
|
|
$user->avatar = $avatar;
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->persist($user); // save cascaded to avatar
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->commit();
|
2009-01-03 19:50:13 +00:00
|
|
|
|
|
|
|
$this->assertTrue(is_numeric($user->id));
|
|
|
|
$this->assertTrue(is_numeric($avatar->id));
|
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertEquals(1, count($userPersister->getInserts()));
|
2009-01-03 19:50:13 +00:00
|
|
|
$this->assertEquals(0, count($userPersister->getUpdates()));
|
|
|
|
$this->assertEquals(0, count($userPersister->getDeletes()));
|
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->assertEquals(1, count($avatarPersister->getInserts()));
|
2009-01-03 19:50:13 +00:00
|
|
|
$this->assertEquals(0, count($avatarPersister->getUpdates()));
|
|
|
|
$this->assertEquals(0, count($avatarPersister->getDeletes()));
|
2008-08-22 09:05:14 +00:00
|
|
|
}
|
2009-01-03 19:50:13 +00:00
|
|
|
|
2009-04-24 21:08:59 +00:00
|
|
|
public function testChangeTrackingNotify()
|
2009-01-03 19:50:13 +00:00
|
|
|
{
|
2015-01-18 00:37:21 +01:00
|
|
|
$persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\ORM\NotifyChangedEntity'));
|
2009-05-19 16:11:08 +00:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedEntity', $persister);
|
2015-01-18 00:37:21 +01:00
|
|
|
$itemPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\ORM\NotifyChangedRelatedItem'));
|
2010-07-15 15:52:42 +02:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedRelatedItem', $itemPersister);
|
2009-05-19 16:11:08 +00:00
|
|
|
|
2009-04-24 21:08:59 +00:00
|
|
|
$entity = new NotifyChangedEntity;
|
|
|
|
$entity->setData('thedata');
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->persist($entity);
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2009-07-19 16:54:53 +00:00
|
|
|
$this->_unitOfWork->commit();
|
2010-07-15 15:52:42 +02:00
|
|
|
$this->assertEquals(1, count($persister->getInserts()));
|
|
|
|
$persister->reset();
|
2009-04-24 21:08:59 +00:00
|
|
|
|
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
|
|
|
|
|
|
|
$entity->setData('newdata');
|
2010-05-01 12:14:16 +02:00
|
|
|
$entity->setTransient('newtransientvalue');
|
2009-04-24 21:08:59 +00:00
|
|
|
|
2010-07-15 15:52:42 +02:00
|
|
|
$this->assertTrue($this->_unitOfWork->isScheduledForDirtyCheck($entity));
|
2009-04-24 21:08:59 +00:00
|
|
|
|
|
|
|
$this->assertEquals(array('data' => array('thedata', 'newdata')), $this->_unitOfWork->getEntityChangeSet($entity));
|
2010-07-15 15:52:42 +02:00
|
|
|
|
|
|
|
$item = new NotifyChangedRelatedItem();
|
|
|
|
$entity->getItems()->add($item);
|
|
|
|
$item->setOwner($entity);
|
|
|
|
$this->_unitOfWork->persist($item);
|
|
|
|
|
|
|
|
$this->_unitOfWork->commit();
|
|
|
|
$this->assertEquals(1, count($itemPersister->getInserts()));
|
|
|
|
$persister->reset();
|
|
|
|
$itemPersister->reset();
|
|
|
|
|
2011-12-19 22:56:19 +01:00
|
|
|
|
2010-07-15 15:52:42 +02:00
|
|
|
$entity->getItems()->removeElement($item);
|
|
|
|
$item->setOwner(null);
|
|
|
|
$this->assertTrue($entity->getItems()->isDirty());
|
|
|
|
$this->_unitOfWork->commit();
|
|
|
|
$updates = $itemPersister->getUpdates();
|
|
|
|
$this->assertEquals(1, count($updates));
|
|
|
|
$this->assertTrue($updates[0] === $item);
|
2009-01-03 19:50:13 +00:00
|
|
|
}
|
2009-04-24 21:08:59 +00:00
|
|
|
|
2010-07-04 18:55:49 +02:00
|
|
|
public function testGetEntityStateOnVersionedEntityWithAssignedIdentifier()
|
2008-07-20 20:13:24 +00:00
|
|
|
{
|
2015-01-18 00:37:21 +01:00
|
|
|
$persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity'));
|
2010-07-04 18:55:49 +02:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity', $persister);
|
|
|
|
|
|
|
|
$e = new VersionedAssignedIdentifierEntity();
|
|
|
|
$e->id = 42;
|
|
|
|
$this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($e));
|
|
|
|
$this->assertFalse($persister->isExistsCalled());
|
2008-07-20 20:13:24 +00:00
|
|
|
}
|
2010-07-04 18:55:49 +02:00
|
|
|
|
|
|
|
public function testGetEntityStateWithAssignedIdentity()
|
2008-07-20 20:13:24 +00:00
|
|
|
{
|
2015-01-18 00:37:21 +01:00
|
|
|
$persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'));
|
2010-07-04 18:55:49 +02:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\CMS\CmsPhonenumber', $persister);
|
|
|
|
|
2016-05-11 01:55:12 +07:00
|
|
|
$ph = new CmsPhonenumber();
|
2010-07-04 18:55:49 +02:00
|
|
|
$ph->phonenumber = '12345';
|
|
|
|
|
|
|
|
$this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($ph));
|
|
|
|
$this->assertTrue($persister->isExistsCalled());
|
|
|
|
|
|
|
|
$persister->reset();
|
|
|
|
|
2010-07-08 00:20:54 +02:00
|
|
|
// if the entity is already managed the exists() check should be skipped
|
2010-07-04 18:55:49 +02:00
|
|
|
$this->_unitOfWork->registerManaged($ph, array('phonenumber' => '12345'), array());
|
|
|
|
$this->assertEquals(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($ph));
|
|
|
|
$this->assertFalse($persister->isExistsCalled());
|
2016-05-11 01:55:12 +07:00
|
|
|
$ph2 = new CmsPhonenumber();
|
2010-07-04 18:55:49 +02:00
|
|
|
$ph2->phonenumber = '12345';
|
|
|
|
$this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_unitOfWork->getEntityState($ph2));
|
|
|
|
$this->assertFalse($persister->isExistsCalled());
|
2008-07-20 20:13:24 +00:00
|
|
|
}
|
2012-10-19 09:15:07 +02:00
|
|
|
|
|
|
|
/**
|
2015-01-18 00:37:21 +01:00
|
|
|
* DDC-2086 [GH-484] Prevented 'Undefined index' notice when updating.
|
2012-10-19 09:15:07 +02:00
|
|
|
*/
|
|
|
|
public function testNoUndefinedIndexNoticeOnScheduleForUpdateWithoutChanges()
|
|
|
|
{
|
|
|
|
// Setup fake persister and id generator
|
2015-01-18 00:37:21 +01:00
|
|
|
$userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser'));
|
|
|
|
$userPersister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
2012-10-19 09:15:07 +02:00
|
|
|
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
|
|
|
|
|
|
|
|
// Create a test user
|
|
|
|
$user = new ForumUser();
|
|
|
|
$user->name = 'Jasper';
|
|
|
|
$this->_unitOfWork->persist($user);
|
|
|
|
$this->_unitOfWork->commit();
|
|
|
|
|
|
|
|
// Schedule user for update without changes
|
|
|
|
$this->_unitOfWork->scheduleForUpdate($user);
|
|
|
|
|
|
|
|
// This commit should not raise an E_NOTICE
|
|
|
|
$this->_unitOfWork->commit();
|
|
|
|
}
|
2013-05-01 19:39:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @group DDC-1984
|
|
|
|
*/
|
|
|
|
public function testLockWithoutEntityThrowsException()
|
|
|
|
{
|
2016-06-18 13:01:59 +02:00
|
|
|
$this->expectException(\InvalidArgumentException::class);
|
2013-05-01 19:39:21 +02:00
|
|
|
$this->_unitOfWork->lock(null, null, null);
|
|
|
|
}
|
2015-01-18 00:37:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @group DDC-3490
|
|
|
|
*
|
|
|
|
* @dataProvider invalidAssociationValuesDataProvider
|
|
|
|
*
|
|
|
|
* @param mixed $invalidValue
|
|
|
|
*/
|
2015-01-18 00:55:40 +01:00
|
|
|
public function testRejectsPersistenceOfObjectsWithInvalidAssociationValue($invalidValue)
|
|
|
|
{
|
|
|
|
$this->_unitOfWork->setEntityPersister(
|
|
|
|
'Doctrine\Tests\Models\Forum\ForumUser',
|
|
|
|
new EntityPersisterMock(
|
|
|
|
$this->_emMock,
|
|
|
|
$this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser')
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$user = new ForumUser();
|
|
|
|
$user->username = 'John';
|
|
|
|
$user->avatar = $invalidValue;
|
|
|
|
|
2016-06-18 13:01:59 +02:00
|
|
|
$this->expectException(\Doctrine\ORM\ORMInvalidArgumentException::class);
|
2015-01-18 00:55:40 +01:00
|
|
|
|
|
|
|
$this->_unitOfWork->persist($user);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @group DDC-3490
|
|
|
|
*
|
|
|
|
* @dataProvider invalidAssociationValuesDataProvider
|
|
|
|
*
|
|
|
|
* @param mixed $invalidValue
|
|
|
|
*/
|
|
|
|
public function testRejectsChangeSetComputationForObjectsWithInvalidAssociationValue($invalidValue)
|
2015-01-18 00:37:21 +01:00
|
|
|
{
|
|
|
|
$metadata = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser');
|
|
|
|
|
|
|
|
$this->_unitOfWork->setEntityPersister(
|
|
|
|
'Doctrine\Tests\Models\Forum\ForumUser',
|
|
|
|
new EntityPersisterMock($this->_emMock, $metadata)
|
|
|
|
);
|
|
|
|
|
2015-01-18 00:55:40 +01:00
|
|
|
$user = new ForumUser();
|
|
|
|
|
|
|
|
$this->_unitOfWork->persist($user);
|
|
|
|
|
2015-01-18 00:37:21 +01:00
|
|
|
$user->username = 'John';
|
|
|
|
$user->avatar = $invalidValue;
|
|
|
|
|
2016-06-18 13:01:59 +02:00
|
|
|
$this->expectException(\Doctrine\ORM\ORMInvalidArgumentException::class);
|
2015-01-18 00:37:21 +01:00
|
|
|
|
|
|
|
$this->_unitOfWork->computeChangeSet($metadata, $user);
|
|
|
|
}
|
|
|
|
|
2015-03-17 22:31:05 +00:00
|
|
|
/**
|
|
|
|
* @group DDC-3619
|
|
|
|
* @group 1338
|
|
|
|
*/
|
2015-03-17 22:30:06 +00:00
|
|
|
public function testRemovedAndRePersistedEntitiesAreInTheIdentityMapAndAreNotGarbageCollected()
|
|
|
|
{
|
|
|
|
$entity = new ForumUser();
|
|
|
|
$entity->id = 123;
|
|
|
|
|
|
|
|
$this->_unitOfWork->registerManaged($entity, array('id' => 123), array());
|
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
|
|
|
|
|
|
|
$this->_unitOfWork->remove($entity);
|
|
|
|
$this->assertFalse($this->_unitOfWork->isInIdentityMap($entity));
|
|
|
|
|
|
|
|
$this->_unitOfWork->persist($entity);
|
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
|
|
|
}
|
|
|
|
|
2016-06-05 23:54:16 +02:00
|
|
|
/**
|
|
|
|
* @group 5849
|
|
|
|
* @group 5850
|
|
|
|
*/
|
2016-06-03 16:13:52 +02:00
|
|
|
public function testPersistedEntityAndClearManager()
|
|
|
|
{
|
2016-06-06 00:08:26 +02:00
|
|
|
$entity1 = new City(123, 'London');
|
|
|
|
$entity2 = new Country(456, 'United Kingdom');
|
2016-06-03 16:13:52 +02:00
|
|
|
|
|
|
|
$this->_unitOfWork->persist($entity1);
|
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity1));
|
|
|
|
|
|
|
|
$this->_unitOfWork->persist($entity2);
|
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity2));
|
|
|
|
|
2016-06-06 00:08:26 +02:00
|
|
|
$this->_unitOfWork->clear(Country::class);
|
2016-06-03 16:13:52 +02:00
|
|
|
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity1));
|
|
|
|
$this->assertFalse($this->_unitOfWork->isInIdentityMap($entity2));
|
|
|
|
$this->assertTrue($this->_unitOfWork->isScheduledForInsert($entity1));
|
|
|
|
$this->assertFalse($this->_unitOfWork->isScheduledForInsert($entity2));
|
|
|
|
}
|
|
|
|
|
2015-01-18 00:37:21 +01:00
|
|
|
/**
|
|
|
|
* Data Provider
|
|
|
|
*
|
|
|
|
* @return mixed[][]
|
|
|
|
*/
|
|
|
|
public function invalidAssociationValuesDataProvider()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
['foo'],
|
|
|
|
[['foo']],
|
|
|
|
[''],
|
|
|
|
[[]],
|
|
|
|
[new stdClass()],
|
|
|
|
[new ArrayCollection()],
|
|
|
|
];
|
|
|
|
}
|
2016-07-07 19:27:49 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider entitiesWithValidIdentifiersProvider
|
|
|
|
*
|
|
|
|
* @param object $entity
|
2016-07-07 19:34:24 +02:00
|
|
|
* @param string $idHash
|
2016-07-07 19:27:49 +02:00
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2016-07-07 19:34:24 +02:00
|
|
|
public function testAddToIdentityMapValidIdentifiers($entity, $idHash)
|
2016-07-07 19:27:49 +02:00
|
|
|
{
|
2016-07-07 20:28:21 +02:00
|
|
|
$this->_unitOfWork->persist($entity);
|
2016-07-07 19:27:49 +02:00
|
|
|
$this->_unitOfWork->addToIdentityMap($entity);
|
|
|
|
|
2016-07-07 19:34:24 +02:00
|
|
|
self::assertSame($entity, $this->_unitOfWork->getByIdHash($idHash, get_class($entity)));
|
2016-07-07 19:27:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function entitiesWithValidIdentifiersProvider()
|
|
|
|
{
|
|
|
|
$emptyString = new EntityWithStringIdentifier();
|
|
|
|
|
|
|
|
$emptyString->id = '';
|
|
|
|
|
|
|
|
$nonEmptyString = new EntityWithStringIdentifier();
|
|
|
|
|
2016-07-07 19:35:39 +02:00
|
|
|
$nonEmptyString->id = uniqid('id', true);
|
2016-07-07 19:27:49 +02:00
|
|
|
|
2016-07-07 19:34:24 +02:00
|
|
|
$emptyStrings = new EntityWithCompositeStringIdentifier();
|
|
|
|
|
|
|
|
$emptyStrings->id1 = '';
|
|
|
|
$emptyStrings->id2 = '';
|
|
|
|
|
2016-07-07 19:35:39 +02:00
|
|
|
$nonEmptyStrings = new EntityWithCompositeStringIdentifier();
|
|
|
|
|
|
|
|
$nonEmptyStrings->id1 = uniqid('id1', true);
|
|
|
|
$nonEmptyStrings->id2 = uniqid('id2', true);
|
|
|
|
|
2016-07-07 19:38:48 +02:00
|
|
|
$booleanTrue = new EntityWithBooleanIdentifier();
|
|
|
|
|
|
|
|
$booleanTrue->id = true;
|
|
|
|
|
|
|
|
$booleanFalse = new EntityWithBooleanIdentifier();
|
|
|
|
|
|
|
|
$booleanFalse->id = false;
|
|
|
|
|
2016-07-07 19:27:49 +02:00
|
|
|
return [
|
2016-07-07 19:34:24 +02:00
|
|
|
'empty string, single field' => [$emptyString, ''],
|
|
|
|
'non-empty string, single field' => [$nonEmptyString, $nonEmptyString->id],
|
|
|
|
'empty strings, two fields' => [$emptyStrings, ' '],
|
2016-07-07 19:35:39 +02:00
|
|
|
'non-empty strings, two fields' => [$nonEmptyStrings, $nonEmptyStrings->id1 . ' ' . $nonEmptyStrings->id2],
|
2016-07-07 19:38:48 +02:00
|
|
|
'boolean true' => [$booleanTrue, '1'],
|
2016-07-07 19:43:03 +02:00
|
|
|
'boolean false' => [$booleanFalse, ''],
|
2016-07-07 19:27:49 +02:00
|
|
|
];
|
|
|
|
}
|
2016-07-07 19:58:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider entitiesWithInvalidIdentifiersProvider
|
|
|
|
*
|
|
|
|
* @param object $entity
|
2016-07-07 20:28:21 +02:00
|
|
|
* @param array $identifier
|
2016-07-07 19:58:43 +02:00
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2016-07-07 20:28:21 +02:00
|
|
|
public function testAddToIdentityMapInvalidIdentifiers($entity, array $identifier)
|
2016-07-07 19:58:43 +02:00
|
|
|
{
|
|
|
|
$this->expectException(ORMInvalidArgumentException::class);
|
|
|
|
|
2016-07-07 20:28:21 +02:00
|
|
|
$this->_unitOfWork->registerManaged($entity, $identifier, []);
|
2016-07-07 19:58:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function entitiesWithInvalidIdentifiersProvider()
|
|
|
|
{
|
2016-07-07 20:08:24 +02:00
|
|
|
$firstNullString = new EntityWithCompositeStringIdentifier();
|
2016-07-07 19:58:43 +02:00
|
|
|
|
2016-07-07 20:08:24 +02:00
|
|
|
$firstNullString->id2 = uniqid('id2', true);
|
2016-07-07 19:58:43 +02:00
|
|
|
|
2016-07-07 20:08:24 +02:00
|
|
|
$secondNullString = new EntityWithCompositeStringIdentifier();
|
2016-07-07 19:58:43 +02:00
|
|
|
|
2016-07-07 20:08:24 +02:00
|
|
|
$secondNullString->id1 = uniqid('id1', true);
|
2016-07-07 19:58:43 +02:00
|
|
|
|
|
|
|
return [
|
2016-07-07 20:28:21 +02:00
|
|
|
'null string, single field' => [new EntityWithStringIdentifier(), ['id' => null]],
|
|
|
|
'null strings, two fields' => [new EntityWithCompositeStringIdentifier(), ['id1' => null, 'id2' => null]],
|
|
|
|
'first null string, two fields' => [$firstNullString, ['id1' => null, 'id2' => $firstNullString->id2]],
|
|
|
|
'second null string, two fields' => [$secondNullString, ['id1' => $secondNullString->id1, 'id2' => null]],
|
2016-07-07 19:58:43 +02:00
|
|
|
];
|
|
|
|
}
|
2009-04-24 21:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-05-29 10:23:13 +00:00
|
|
|
* @Entity
|
2009-04-24 21:08:59 +00:00
|
|
|
*/
|
2015-01-18 00:37:21 +01:00
|
|
|
class NotifyChangedEntity implements NotifyPropertyChanged
|
2009-04-24 21:08:59 +00:00
|
|
|
{
|
|
|
|
private $_listeners = array();
|
|
|
|
/**
|
2009-05-29 10:23:13 +00:00
|
|
|
* @Id
|
|
|
|
* @Column(type="integer")
|
2010-07-15 15:52:42 +02:00
|
|
|
* @GeneratedValue
|
2009-04-24 21:08:59 +00:00
|
|
|
*/
|
|
|
|
private $id;
|
|
|
|
/**
|
2009-05-29 10:23:13 +00:00
|
|
|
* @Column(type="string")
|
2009-04-24 21:08:59 +00:00
|
|
|
*/
|
|
|
|
private $data;
|
|
|
|
|
2010-05-01 12:14:16 +02:00
|
|
|
private $transient; // not persisted
|
|
|
|
|
2010-07-15 15:52:42 +02:00
|
|
|
/** @OneToMany(targetEntity="NotifyChangedRelatedItem", mappedBy="owner") */
|
|
|
|
private $items;
|
|
|
|
|
|
|
|
public function __construct() {
|
2015-01-18 00:37:21 +01:00
|
|
|
$this->items = new ArrayCollection;
|
2010-07-15 15:52:42 +02:00
|
|
|
}
|
|
|
|
|
2009-04-24 21:08:59 +00:00
|
|
|
public function getId() {
|
|
|
|
return $this->id;
|
|
|
|
}
|
|
|
|
|
2010-07-15 15:52:42 +02:00
|
|
|
public function getItems() {
|
|
|
|
return $this->items;
|
|
|
|
}
|
|
|
|
|
2010-05-01 12:14:16 +02:00
|
|
|
public function setTransient($value) {
|
|
|
|
if ($value != $this->transient) {
|
|
|
|
$this->_onPropertyChanged('transient', $this->transient, $value);
|
|
|
|
$this->transient = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-24 21:08:59 +00:00
|
|
|
public function getData() {
|
|
|
|
return $this->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setData($data) {
|
|
|
|
if ($data != $this->data) {
|
|
|
|
$this->_onPropertyChanged('data', $this->data, $data);
|
|
|
|
$this->data = $data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-18 00:37:21 +01:00
|
|
|
public function addPropertyChangedListener(PropertyChangedListener $listener)
|
2009-04-24 21:08:59 +00:00
|
|
|
{
|
|
|
|
$this->_listeners[] = $listener;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function _onPropertyChanged($propName, $oldValue, $newValue) {
|
|
|
|
if ($this->_listeners) {
|
|
|
|
foreach ($this->_listeners as $listener) {
|
|
|
|
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-07-04 18:55:49 +02:00
|
|
|
}
|
|
|
|
|
2010-07-15 15:52:42 +02:00
|
|
|
/** @Entity */
|
|
|
|
class NotifyChangedRelatedItem
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @Id
|
|
|
|
* @Column(type="integer")
|
|
|
|
* @GeneratedValue
|
|
|
|
*/
|
|
|
|
private $id;
|
|
|
|
|
|
|
|
/** @ManyToOne(targetEntity="NotifyChangedEntity", inversedBy="items") */
|
|
|
|
private $owner;
|
|
|
|
|
|
|
|
public function getId() {
|
|
|
|
return $this->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getOwner() {
|
|
|
|
return $this->owner;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setOwner($owner) {
|
|
|
|
$this->owner = $owner;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-04 18:55:49 +02:00
|
|
|
/** @Entity */
|
|
|
|
class VersionedAssignedIdentifierEntity
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @Id @Column(type="integer")
|
|
|
|
*/
|
|
|
|
public $id;
|
|
|
|
/**
|
|
|
|
* @Version @Column(type="integer")
|
|
|
|
*/
|
|
|
|
public $version;
|
2012-10-19 09:15:07 +02:00
|
|
|
}
|
2016-07-07 19:27:49 +02:00
|
|
|
|
|
|
|
/** @Entity */
|
|
|
|
class EntityWithStringIdentifier
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @Id @Column(type="string")
|
|
|
|
*
|
|
|
|
* @var string|null
|
|
|
|
*/
|
|
|
|
public $id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @Entity */
|
|
|
|
class EntityWithBooleanIdentifier
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @Id @Column(type="boolean")
|
|
|
|
*
|
|
|
|
* @var bool|null
|
|
|
|
*/
|
|
|
|
public $id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @Entity */
|
|
|
|
class EntityWithCompositeStringIdentifier
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @Id @Column(type="string")
|
|
|
|
*
|
|
|
|
* @var string|null
|
|
|
|
*/
|
|
|
|
public $id1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @Id @Column(type="string")
|
|
|
|
*
|
|
|
|
* @var string|null
|
|
|
|
*/
|
|
|
|
public $id2;
|
|
|
|
}
|