Passed
Pull Request — 2.6 (#7318)
by
unknown
09:54
created

GH7318Test::setUp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Doctrine\Tests\ORM\Functional\Ticket;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\EventManager;
7
use Doctrine\ORM\Mapping as ORM;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\PersistentCollection;
10
use Doctrine\Tests\Mocks\ConnectionMock;
11
use Doctrine\Tests\Mocks\DriverMock;
12
use Doctrine\Tests\Mocks\EntityManagerMock;
13
use Doctrine\Tests\Mocks\EntityPersisterMock;
14
use Doctrine\Tests\Mocks\UnitOfWorkMock;
15
use Doctrine\Tests\OrmTestCase;
16
17
final class GH7318Test extends OrmTestCase
18
{
19
    /**
20
     * SUT
21
     *
22
     * @var UnitOfWorkMock
23
     */
24
    private $_unitOfWork;
25
26
    /**
27
     * The EntityManager mock that provides the mock persisters
28
     *
29
     * @var EntityManagerMock
30
     */
31
    private $_emMock;
32
33
    protected function setUp()
34
    {
35
        parent::setUp();
36
        $connectionMock = new ConnectionMock([], new DriverMock());
37
        $eventManager = $this->getMockBuilder(EventManager::class)->getMock();
38
        $this->_emMock = EntityManagerMock::create($connectionMock, null, $eventManager);
39
        $this->_unitOfWork = new UnitOfWorkMock($this->_emMock);
40
        $this->_emMock->setUnitOfWork($this->_unitOfWork);
41
    }
42
43
    /**
44
     * This test covers the bug where computing entity change set of an already managed object with an auto-generated id
45
     * stored incorrect original entity data, which was missing that id.
46
     */
47
    public function testComputeChangesetPreservesOriginalIdOnSubsequentCalls()
48
    {
49
        // Setup fake persister and id generator for identity generation
50
        $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata(GH7318Entity::class));
51
        $this->_unitOfWork->setEntityPersister(GH7318Entity::class, $persister);
52
        $persister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
53
54
        // Create and persist new object
55
        $object = new GH7318Entity();
56
        $object->data = 'foo';
57
        $this->_unitOfWork->persist($object);
58
        // this will call UnitOfWork::computeChangeSet() internally
59
        $this->_unitOfWork->commit();
60
        // should have an id
61
        $this->assertInternalType('numeric', $object->id);
62
63
        // preserve original entity data
64
        $originalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
65
66
        // make identical change to the object and preserved original data
67
        $object->data = 'bar';
68
        $originalEntityData['data'] = 'bar';
69
70
        // Flush object again
71
        // this will call UnitOfWork::computeChangeSet() internally
72
        $this->_unitOfWork->commit();
73
74
        $newOriginalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
75
76
        // $newOriginalEntityData after second persisting should match the original one
77
        $this->assertSame($originalEntityData, $newOriginalEntityData, 'Original entity data of a managed entity doesn\'t match expected value.');
78
    }
79
80
    /**
81
     * This test covers the bug where re-computing entity change set of an already managed object
82
     * with an auto-generated id stored incorrect original entity data, which was missing that id.
83
     * In practice it caused issues when calling `recomputeSingleEntityChangeSet` in an onFlush event listener.
84
     */
85
    public function testRecomputeEntityChangesetPreservesOriginalIdOnSubsequentCalls()
86
    {
87
        // Setup fake persister and id generator for identity generation
88
        $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata(GH7318Entity::class));
89
        $this->_unitOfWork->setEntityPersister(GH7318Entity::class, $persister);
90
        $persister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
91
92
        // Create and persist new object
93
        $object = new GH7318Entity();
94
        $object->data = 'foo';
95
        $this->_unitOfWork->persist($object);
96
        // this will call UnitOfWork::computeChangeSet() internally
97
        $this->_unitOfWork->commit();
98
        // should have an id
99
        $this->assertInternalType('numeric', $object->id);
100
101
        // preserve original entity data
102
        $originalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
103
104
        // make identical change to the object and preserved original data
105
        $object->data = 'bar';
106
        $originalEntityData['data'] = 'bar';
107
108
        // recompute change set
109
        $metadata = $this->_emMock->getClassMetadata(GH7318Entity::class);
110
        $this->_unitOfWork->recomputeSingleEntityChangeSet($metadata, $object);
111
        $newOriginalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
112
113
        // $newOriginalEntityData after second persisting should match the original one
114
        $this->assertSame($originalEntityData, $newOriginalEntityData, 'Original entity data of a managed entity doesn\'t match expected value.');
115
    }
116
117
    /**
118
     * This test covers the bug where after computing change sets for a managed object having *-to-many relation,
119
     * (since the object is persisted, collection is instance of PersistentCollection)
120
     * original entity data stored in UnitOfWork was missing that collection.
121
     */
122
    public function testComputeChangesetPreservesPersistentCollectionsInOriginalEntityData()
123
    {
124
        // Setup fake persister and id generator for identity generation
125
        $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata(PersistentCollectionOwner::class));
126
        $this->_unitOfWork->setEntityPersister(PersistentCollectionOwner::class, $persister);
127
        $persister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
128
129
        // Create and persist new object
130
        $object = new PersistentCollectionOwner();
131
        $object->data = 'foo';
132
        $object->addElement(new PersistentCollectionElement());
133
        $this->_unitOfWork->persist($object);
134
        // this will call UnitOfWork::computeChangeSet() internally
135
        $this->_unitOfWork->commit();
136
        // should have an id
137
        $this->assertInternalType('numeric', $object->id);
138
        // ArrayCollection should become PersistentCollection after commit
139
        $this->assertInstanceOf(PersistentCollection::class, $object->getCollection());
140
141
        // preserve original entity data
142
        $originalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
143
        $this->assertTrue(
144
            isset($originalEntityData['collection'])
145
            && $originalEntityData['collection'] instanceof PersistentCollection,
146
            'Original entity data should contain a persistent collection after persisting object first time.'
147
        );
148
149
        // make identical change to the object and preserved original data
150
        $object->data = 'bar';
151
        $originalEntityData['data'] = 'bar';
152
153
        // this will call UnitOfWork::computeChangeSet() internally
154
        $this->_unitOfWork->commit();
155
        $newOriginalEntityData = $this->_unitOfWork->getOriginalEntityData($object);
156
        $this->assertTrue(
157
            isset($newOriginalEntityData['collection'])
158
            && $newOriginalEntityData['collection'] instanceof PersistentCollection,
159
            'Original entity data should contain a persistent collection after persisting object second time.'
160
        );
161
162
        // $newOriginalEntityData after second persisting should match the original one
163
        $this->assertSame($originalEntityData, $newOriginalEntityData, 'Original entity data of a managed entity doesn\'t match expected value.');
164
    }
165
}
166
167
/**
168
 * @Entity
169
 */
170
class GH7318Entity
171
{
172
    /**
173
     * @Id
174
     * @Column(type="integer")
175
     * @GeneratedValue
176
     *
177
     * @var int
178
     */
179
    public $id;
180
181
    /**
182
     * @Column(type="string", length=50)
183
     * @var string
184
     */
185
    public $data;
186
}
187
188
/**
189
 * @Entity
190
 */
191
class PersistentCollectionOwner
192
{
193
    /**
194
     * @Id
195
     * @Column(type="integer")
196
     * @GeneratedValue
197
     *
198
     * @var int
199
     */
200
    public $id;
201
202
    /**
203
     * @Column(type="string", length=50)
204
     * @var string
205
     */
206
    public $data;
207
208
    /**
209
     * @var \Doctrine\Common\Collections\Collection
210
     * @OneToMany(targetEntity="PersistentCollectionElement", cascade={"all"}, fetch="EXTRA_LAZY", mappedBy="owner")
211
     */
212
    protected $collection;
213
214
    public function __construct()
215
    {
216
        $this->collection = new ArrayCollection();
217
    }
218
219
    /**
220
     * @param PersistentCollectionElement $element
221
     */
222
    public function addElement(PersistentCollectionElement $element)
223
    {
224
        $this->collection->add($element);
225
    }
226
227
    /**
228
     * @return \Doctrine\Common\Collections\Collection
229
     */
230
    public function getCollection()
231
    {
232
        return $this->collection;
233
    }
234
}
235
236
/**
237
 * @Entity
238
 */
239
class PersistentCollectionElement
240
{
241
    /**
242
     * @Id
243
     * @Column(type="integer")
244
     * @GeneratedValue
245
     *
246
     * @var int
247
     */
248
    public $id;
249
250
    /**
251
     * @ORM\ManyToOne(targetEntity="PersistentCollectionOwner", inversedBy="collection")
252
     *
253
     * @var int
254
     */
255
    public $owner;
256
}
257