Failed Conditions
Pull Request — develop (#6873)
by
unknown
112:44 queued 47:41
created

testCollectionValuedAssociationIdentityMapBehaviorWithRefresh()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 46
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 24
nc 1
nop 0
dl 0
loc 46
rs 8.9411
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Functional;
6
7
use Doctrine\ORM\Query;
8
use Doctrine\Tests\Models\CMS\CmsAddress;
9
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
10
use Doctrine\Tests\Models\CMS\CmsUser;
11
use Doctrine\Tests\OrmFunctionalTestCase;
12
13
/**
14
 * IdentityMapTest
15
 *
16
 * Tests correct behavior and usage of the identity map. Local values and associations
17
 * that are already fetched always prevail, unless explicitly refreshed.
18
 *
19
 * @author Roman Borschel <[email protected]>
20
 */
21
class IdentityMapTest extends OrmFunctionalTestCase
22
{
23
    protected function setUp()
24
    {
25
        $this->useModelSet('cms');
26
        parent::setUp();
27
    }
28
29
    public function testBasicIdentityManagement()
30
    {
31
        $user = new CmsUser;
32
        $user->status = 'dev';
33
        $user->username = 'romanb';
34
        $user->name = 'Roman B.';
35
36
        $address = new CmsAddress;
37
        $address->country = 'de';
38
        $address->zip = 1234;
39
        $address->city = 'Berlin';
40
41
        $user->setAddress($address);
42
43
        $this->em->persist($user);
44
        $this->em->flush();
45
        $this->em->clear();
46
47
        $user2 = $this->em->find(get_class($user), $user->getId());
48
        self::assertNotSame($user2, $user);
49
        $user3 = $this->em->find(get_class($user), $user->getId());
50
        self::assertSame($user2, $user3);
51
52
        $address2 = $this->em->find(get_class($address), $address->getId());
53
        self::assertNotSame($address2, $address);
54
        $address3 = $this->em->find(get_class($address), $address->getId());
55
        self::assertSame($address2, $address3);
56
57
        self::assertSame($user2->getAddress(), $address2); // !!!
58
    }
59
60
    public function testSingleValuedAssociationIdentityMapBehaviorWithRefresh()
61
    {
62
        $address = new CmsAddress;
63
        $address->country = 'de';
64
        $address->zip = '12345';
65
        $address->city = 'Berlin';
66
67
        $user1 = new CmsUser;
68
        $user1->status = 'dev';
69
        $user1->username = 'romanb';
70
        $user1->name = 'Roman B.';
71
72
        $user2 = new CmsUser;
73
        $user2->status = 'dev';
74
        $user2->username = 'gblanco';
75
        $user2->name = 'Guilherme Blanco';
76
77
        $address->setUser($user1);
78
79
        $this->em->persist($address);
80
        $this->em->persist($user1);
81
        $this->em->persist($user2);
82
        $this->em->flush();
83
84
        self::assertSame($user1, $address->user);
85
86
        //external update to CmsAddress
87
        $this->em->getConnection()->executeUpdate('update cms_addresses set user_id = ?', [$user2->getId()]);
88
89
        // But we want to have this external change!
90
        // Solution 1: refresh(), broken atm!
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
91
        $this->em->refresh($address);
92
93
        // Now the association should be "correct", referencing $user2
94
        self::assertSame($user2, $address->user);
95
        self::assertSame($user2->address, $address); // check back reference also
96
97
        // Attention! refreshes can result in broken bidirectional associations! this is currently expected!
98
        // $user1 still points to $address!
99
        self::assertSame($user1->address, $address);
100
    }
101
102
    public function testSingleValuedAssociationIdentityMapBehaviorWithRefreshQuery()
103
    {
104
        $address = new CmsAddress;
105
        $address->country = 'de';
106
        $address->zip = '12345';
107
        $address->city = 'Berlin';
108
109
        $user1 = new CmsUser;
110
        $user1->status = 'dev';
111
        $user1->username = 'romanb';
112
        $user1->name = 'Roman B.';
113
114
        $user2 = new CmsUser;
115
        $user2->status = 'dev';
116
        $user2->username = 'gblanco';
117
        $user2->name = 'Guilherme Blanco';
118
119
        $address->setUser($user1);
120
121
        $this->em->persist($address);
122
        $this->em->persist($user1);
123
        $this->em->persist($user2);
124
        $this->em->flush();
125
126
127
        self::assertSame($user1, $address->user);
128
129
        //external update to CmsAddress
130
        $this->em->getConnection()->executeUpdate('update cms_addresses set user_id = ?', [$user2->getId()]);
131
132
        //select
133
        $q = $this->em->createQuery('select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u');
134
        $address2 = $q->getSingleResult();
135
136
        self::assertSame($address, $address2);
137
138
        // Should still be $user1
139
        self::assertSame($user1, $address2->user);
140
        self::assertNull($user2->address);
141
142
        // But we want to have this external change!
143
        // Solution 2: Alternatively, a refresh query should work
144
        $q = $this->em->createQuery('select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u');
145
        $q->setHint(Query::HINT_REFRESH, true);
146
        $address3 = $q->getSingleResult();
147
148
        self::assertSame($address, $address3); // should still be the same, always from identity map
149
150
        // Now the association should be "correct", referencing $user2
151
        self::assertSame($user2, $address2->user);
152
        self::assertSame($user2->address, $address2); // check back reference also
153
154
        // Attention! refreshes can result in broken bidirectional associations! this is currently expected!
155
        // $user1 still points to $address2!
156
        self::assertSame($user1->address, $address2);
157
    }
158
159
    public function testCollectionValuedAssociationIdentityMapBehaviorWithRefreshQuery()
160
    {
161
        $user = new CmsUser;
162
        $user->status = 'dev';
163
        $user->username = 'romanb';
164
        $user->name = 'Roman B.';
165
166
        $phone1 = new CmsPhonenumber;
167
        $phone1->phonenumber = 123;
168
169
        $phone2 = new CmsPhonenumber;
170
        $phone2->phonenumber = 234;
171
172
        $phone3 = new CmsPhonenumber;
173
        $phone3->phonenumber = 345;
174
175
        $user->addPhonenumber($phone1);
176
        $user->addPhonenumber($phone2);
177
        $user->addPhonenumber($phone3);
178
179
        $this->em->persist($user); // cascaded to phone numbers
180
        $this->em->flush();
181
182
        self::assertCount(3, $user->getPhonenumbers());
183
        self::assertFalse($user->getPhonenumbers()->isDirty());
0 ignored issues
show
Bug introduced by
The method isDirty() does not exist on Countable. It seems like you code against a sub-type of Countable such as Doctrine\ORM\PersistentCollection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

183
        self::assertFalse($user->getPhonenumbers()->/** @scrutinizer ignore-call */ isDirty());
Loading history...
Bug introduced by
The method isDirty() does not exist on Traversable. It seems like you code against a sub-type of Traversable such as Doctrine\ORM\PersistentCollection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

183
        self::assertFalse($user->getPhonenumbers()->/** @scrutinizer ignore-call */ isDirty());
Loading history...
Bug introduced by
The method isDirty() does not exist on Doctrine\Common\Collections\ArrayCollection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

183
        self::assertFalse($user->getPhonenumbers()->/** @scrutinizer ignore-call */ isDirty());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
184
185
        //external update to CmsAddress
186
        $this->em->getConnection()->executeUpdate('insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)', [999, $user->getId()]
187
        );
188
189
        //select
190
        $q = $this->em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p');
191
        $user2 = $q->getSingleResult();
192
193
        self::assertSame($user, $user2);
194
195
        // Should still be the same 3 phonenumbers
196
        self::assertCount(3, $user2->getPhonenumbers());
197
198
        // But we want to have this external change!
199
        // Solution 1: refresh().
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
200
        //$this->em->refresh($user2); broken atm!
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
201
        // Solution 2: Alternatively, a refresh query should work
202
        $q = $this->em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p');
203
        $q->setHint(Query::HINT_REFRESH, true);
204
        $user3 = $q->getSingleResult();
205
206
        self::assertSame($user, $user3); // should still be the same, always from identity map
207
208
        // Now the collection should be refreshed with correct count
209
        self::assertCount(4, $user3->getPhonenumbers());
210
    }
211
212
    public function testCollectionValuedAssociationIdentityMapBehaviorWithRefresh()
213
    {
214
        $user = new CmsUser;
215
        $user->status = 'dev';
216
        $user->username = 'romanb';
217
        $user->name = 'Roman B.';
218
219
        $phone1 = new CmsPhonenumber;
220
        $phone1->phonenumber = 123;
221
222
        $phone2 = new CmsPhonenumber;
223
        $phone2->phonenumber = 234;
224
225
        $phone3 = new CmsPhonenumber;
226
        $phone3->phonenumber = 345;
227
228
        $user->addPhonenumber($phone1);
229
        $user->addPhonenumber($phone2);
230
        $user->addPhonenumber($phone3);
231
232
        $this->em->persist($user); // cascaded to phone numbers
233
        $this->em->flush();
234
235
        self::assertCount(3, $user->getPhonenumbers());
236
237
        //external update to CmsAddress
238
        $this->em->getConnection()->executeUpdate('insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)', [999, $user->getId()]
239
        );
240
241
        //select
242
        $q = $this->em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p');
243
        $user2 = $q->getSingleResult();
244
245
        self::assertSame($user, $user2);
246
247
        // Should still be the same 3 phonenumbers
248
        self::assertCount(3, $user2->getPhonenumbers());
249
250
        // But we want to have this external change!
251
        // Solution 1: refresh().
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
252
        $this->em->refresh($user2);
253
254
        self::assertSame($user, $user2); // should still be the same, always from identity map
255
256
        // Now the collection should be refreshed with correct count
257
        self::assertCount(4, $user2->getPhonenumbers());
258
    }
259
}
260