Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / orm / tests / Doctrine / Tests / ORM / UnitOfWorkTest.php
1 <?php
2
3 namespace Doctrine\Tests\ORM;
4
5 use Doctrine\ORM\UnitOfWork;
6 use Doctrine\Tests\Mocks\ConnectionMock;
7 use Doctrine\Tests\Mocks\EntityManagerMock;
8 use Doctrine\Tests\Mocks\UnitOfWorkMock;
9 use Doctrine\Tests\Mocks\EntityPersisterMock;
10 use Doctrine\Tests\Mocks\IdentityIdGeneratorMock;
11 use Doctrine\Tests\Models\Forum\ForumUser;
12 use Doctrine\Tests\Models\Forum\ForumAvatar;
13
14 require_once __DIR__ . '/../TestInit.php';
15
16 /**
17  * UnitOfWork tests.
18  */
19 class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
20 {
21     // SUT
22     private $_unitOfWork;
23     // Provides a sequence mock to the UnitOfWork
24     private $_connectionMock;
25     // The EntityManager mock that provides the mock persisters
26     private $_emMock;
27
28     protected function setUp() {
29         parent::setUp();
30         $this->_connectionMock = new ConnectionMock(array(), new \Doctrine\Tests\Mocks\DriverMock());
31         $this->_emMock = EntityManagerMock::create($this->_connectionMock);
32         // SUT
33         $this->_unitOfWork = new UnitOfWorkMock($this->_emMock);
34         $this->_emMock->setUnitOfWork($this->_unitOfWork);
35     }
36
37     protected function tearDown() {
38     }
39
40     public function testRegisterRemovedOnNewEntityIsIgnored()
41     {
42         $user = new ForumUser();
43         $user->username = 'romanb';
44         $this->assertFalse($this->_unitOfWork->isScheduledForDelete($user));
45         $this->_unitOfWork->scheduleForDelete($user);
46         $this->assertFalse($this->_unitOfWork->isScheduledForDelete($user));
47     }
48
49
50     /* Operational tests */
51
52     public function testSavingSingleEntityWithIdentityColumnForcesInsert()
53     {
54         // Setup fake persister and id generator for identity generation
55         $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser"));
56         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
57         //$idGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
58         //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $idGeneratorMock);
59         $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
60
61         // Test
62         $user = new ForumUser();
63         $user->username = 'romanb';
64         $this->_unitOfWork->persist($user);
65
66         // Check
67         $this->assertEquals(0, count($userPersister->getInserts()));
68         $this->assertEquals(0, count($userPersister->getUpdates()));
69         $this->assertEquals(0, count($userPersister->getDeletes()));
70         $this->assertFalse($this->_unitOfWork->isInIdentityMap($user));
71         // should no longer be scheduled for insert
72         $this->assertTrue($this->_unitOfWork->isScheduledForInsert($user));
73
74         // Now lets check whether a subsequent commit() does anything
75         $userPersister->reset();
76
77         // Test
78         $this->_unitOfWork->commit();
79
80         // Check.
81         $this->assertEquals(1, count($userPersister->getInserts()));
82         $this->assertEquals(0, count($userPersister->getUpdates()));
83         $this->assertEquals(0, count($userPersister->getDeletes()));
84
85         // should have an id
86         $this->assertTrue(is_numeric($user->id));
87     }
88
89     /**
90      * Tests a scenario where a save() operation is cascaded from a ForumUser
91      * to its associated ForumAvatar, both entities using IDENTITY id generation.
92      */
93     public function testCascadedIdentityColumnInsert()
94     {
95         // Setup fake persister and id generator for identity generation
96         //ForumUser
97         $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser"));
98         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
99         //$userIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
100         //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $userIdGeneratorMock);
101         $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
102         // ForumAvatar
103         $avatarPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumAvatar"));
104         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister);
105         //$avatarIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
106         //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarIdGeneratorMock);
107         $avatarPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
108
109         // Test
110         $user = new ForumUser();
111         $user->username = 'romanb';
112         $avatar = new ForumAvatar();
113         $user->avatar = $avatar;
114         $this->_unitOfWork->persist($user); // save cascaded to avatar
115
116         $this->_unitOfWork->commit();
117
118         $this->assertTrue(is_numeric($user->id));
119         $this->assertTrue(is_numeric($avatar->id));
120
121         $this->assertEquals(1, count($userPersister->getInserts()));
122         $this->assertEquals(0, count($userPersister->getUpdates()));
123         $this->assertEquals(0, count($userPersister->getDeletes()));
124
125         $this->assertEquals(1, count($avatarPersister->getInserts()));
126         $this->assertEquals(0, count($avatarPersister->getUpdates()));
127         $this->assertEquals(0, count($avatarPersister->getDeletes()));
128     }
129
130     public function testChangeTrackingNotify()
131     {
132         $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedEntity"));
133         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedEntity', $persister);
134         $itemPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedRelatedItem"));
135         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedRelatedItem', $itemPersister);
136
137         $entity = new NotifyChangedEntity;
138         $entity->setData('thedata');
139         $this->_unitOfWork->persist($entity);
140
141         $this->_unitOfWork->commit();
142         $this->assertEquals(1, count($persister->getInserts()));
143         $persister->reset();
144
145         $this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
146
147         $entity->setData('newdata');
148         $entity->setTransient('newtransientvalue');
149
150         $this->assertTrue($this->_unitOfWork->isScheduledForDirtyCheck($entity));
151
152         $this->assertEquals(array('data' => array('thedata', 'newdata')), $this->_unitOfWork->getEntityChangeSet($entity));
153
154         $item = new NotifyChangedRelatedItem();
155         $entity->getItems()->add($item);
156         $item->setOwner($entity);
157         $this->_unitOfWork->persist($item);
158
159         $this->_unitOfWork->commit();
160         $this->assertEquals(1, count($itemPersister->getInserts()));
161         $persister->reset();
162         $itemPersister->reset();
163
164
165         $entity->getItems()->removeElement($item);
166         $item->setOwner(null);
167         $this->assertTrue($entity->getItems()->isDirty());
168         $this->_unitOfWork->commit();
169         $updates = $itemPersister->getUpdates();
170         $this->assertEquals(1, count($updates));
171         $this->assertTrue($updates[0] === $item);
172     }
173
174     public function testGetEntityStateOnVersionedEntityWithAssignedIdentifier()
175     {
176         $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity"));
177         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity', $persister);
178
179         $e = new VersionedAssignedIdentifierEntity();
180         $e->id = 42;
181         $this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($e));
182         $this->assertFalse($persister->isExistsCalled());
183     }
184
185     public function testGetEntityStateWithAssignedIdentity()
186     {
187         $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\CMS\CmsPhonenumber"));
188         $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\CMS\CmsPhonenumber', $persister);
189
190         $ph = new \Doctrine\Tests\Models\CMS\CmsPhonenumber();
191         $ph->phonenumber = '12345';
192
193         $this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($ph));
194         $this->assertTrue($persister->isExistsCalled());
195
196         $persister->reset();
197
198         // if the entity is already managed the exists() check should be skipped
199         $this->_unitOfWork->registerManaged($ph, array('phonenumber' => '12345'), array());
200         $this->assertEquals(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($ph));
201         $this->assertFalse($persister->isExistsCalled());
202         $ph2 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber();
203         $ph2->phonenumber = '12345';
204         $this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_unitOfWork->getEntityState($ph2));
205         $this->assertFalse($persister->isExistsCalled());
206     }
207 }
208
209 /**
210  * @Entity
211  */
212 class NotifyChangedEntity implements \Doctrine\Common\NotifyPropertyChanged
213 {
214     private $_listeners = array();
215     /**
216      * @Id
217      * @Column(type="integer")
218      * @GeneratedValue
219      */
220     private $id;
221     /**
222      * @Column(type="string")
223      */
224     private $data;
225
226     private $transient; // not persisted
227
228     /** @OneToMany(targetEntity="NotifyChangedRelatedItem", mappedBy="owner") */
229     private $items;
230
231     public function  __construct() {
232         $this->items = new \Doctrine\Common\Collections\ArrayCollection;
233     }
234
235     public function getId() {
236         return $this->id;
237     }
238
239     public function getItems() {
240         return $this->items;
241     }
242
243     public function setTransient($value) {
244         if ($value != $this->transient) {
245             $this->_onPropertyChanged('transient', $this->transient, $value);
246             $this->transient = $value;
247         }
248     }
249
250     public function getData() {
251         return $this->data;
252     }
253
254     public function setData($data) {
255         if ($data != $this->data) {
256             $this->_onPropertyChanged('data', $this->data, $data);
257             $this->data = $data;
258         }
259     }
260
261     public function addPropertyChangedListener(\Doctrine\Common\PropertyChangedListener $listener)
262     {
263         $this->_listeners[] = $listener;
264     }
265
266     protected function _onPropertyChanged($propName, $oldValue, $newValue) {
267         if ($this->_listeners) {
268             foreach ($this->_listeners as $listener) {
269                 $listener->propertyChanged($this, $propName, $oldValue, $newValue);
270             }
271         }
272     }
273 }
274
275 /** @Entity */
276 class NotifyChangedRelatedItem
277 {
278     /**
279      * @Id
280      * @Column(type="integer")
281      * @GeneratedValue
282      */
283     private $id;
284
285     /** @ManyToOne(targetEntity="NotifyChangedEntity", inversedBy="items") */
286     private $owner;
287
288     public function getId() {
289         return $this->id;
290     }
291
292     public function getOwner() {
293         return $this->owner;
294     }
295
296     public function setOwner($owner) {
297         $this->owner = $owner;
298     }
299 }
300
301 /** @Entity */
302 class VersionedAssignedIdentifierEntity
303 {
304     /**
305      * @Id @Column(type="integer")
306      */
307     public $id;
308     /**
309      * @Version @Column(type="integer")
310      */
311     public $version;
312 }