Failed Conditions
Push — develop ( 14ce66...7b23d3 )
by Guilherme
72:53 queued 07:54
created

ObjectHydratorTest::swapPrivateProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Hydration;
6
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\Mapping\FetchMode;
10
use Doctrine\ORM\PersistentCollection;
11
use Doctrine\ORM\Proxy\ProxyFactory;
12
use Doctrine\ORM\Query;
13
use Doctrine\ORM\Query\ResultSetMapping;
14
use Doctrine\Tests\Mocks\HydratorMockStatement;
15
use Doctrine\Tests\Models\CMS\CmsAddress;
16
use Doctrine\Tests\Models\CMS\CmsArticle;
17
use Doctrine\Tests\Models\CMS\CmsComment;
18
use Doctrine\Tests\Models\CMS\CmsGroup;
19
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
20
use Doctrine\Tests\Models\CMS\CmsUser;
21
use Doctrine\Tests\Models\Company\CompanyEmployee;
22
use Doctrine\Tests\Models\Company\CompanyFixContract;
23
use Doctrine\Tests\Models\Company\CompanyPerson;
24
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
25
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
26
use Doctrine\Tests\Models\Forum\ForumBoard;
27
use Doctrine\Tests\Models\Forum\ForumCategory;
28
use Doctrine\Tests\Models\Hydration\EntityWithArrayDefaultArrayValueM2M;
29
use Doctrine\Tests\Models\Hydration\SimpleEntity;
30
31
class ObjectHydratorTest extends HydrationTestCase
32
{
33
    public function provideDataForUserEntityResult()
34
    {
35
        return [
36
            [0],
37
            ['user'],
38
        ];
39
    }
40
41
    public function provideDataForMultipleRootEntityResult()
42
    {
43
        return [
44
            [0, 0],
45
            ['user', 0],
46
            [0, 'article'],
47
            ['user', 'article'],
48
        ];
49
    }
50
51
    public function provideDataForProductEntityResult()
52
    {
53
        return [
54
            [0],
55
            ['product'],
56
        ];
57
    }
58
59
    /**
60
     * SELECT PARTIAL u.{id,name}
61
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
62
     */
63
    public function testSimpleEntityQuery()
64
    {
65
        $rsm = new ResultSetMapping;
66
        $rsm->addEntityResult(CmsUser::class, 'u');
67
        $rsm->addFieldResult('u', 'u__id', 'id');
68
        $rsm->addFieldResult('u', 'u__name', 'name');
69
70
        // Faked result set
71
        $resultSet = [
72
            [
73
                'u__id' => '1',
74
                'u__name' => 'romanb'
75
            ],
76
            [
77
                'u__id' => '2',
78
                'u__name' => 'jwage'
79
            ]
80
        ];
81
82
        $stmt     = new HydratorMockStatement($resultSet);
83
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
84
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
85
86
        self::assertEquals(2, count($result));
87
88
        self::assertInstanceOf(CmsUser::class, $result[0]);
89
        self::assertInstanceOf(CmsUser::class, $result[1]);
90
91
        self::assertEquals(1, $result[0]->id);
92
        self::assertEquals('romanb', $result[0]->name);
93
94
        self::assertEquals(2, $result[1]->id);
95
        self::assertEquals('jwage', $result[1]->name);
96
    }
97
98
    /**
99
     * SELECT PARTIAL u.{id,name} AS user
100
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
101
     */
102
    public function testSimpleEntityQueryWithAliasedUserEntity()
103
    {
104
        $rsm = new ResultSetMapping;
105
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
106
        $rsm->addFieldResult('u', 'u__id', 'id');
107
        $rsm->addFieldResult('u', 'u__name', 'name');
108
109
        // Faked result set
110
        $resultSet = [
111
            [
112
                'u__id' => '1',
113
                'u__name' => 'romanb'
114
            ],
115
            [
116
                'u__id' => '2',
117
                'u__name' => 'jwage'
118
            ]
119
        ];
120
121
        $stmt     = new HydratorMockStatement($resultSet);
122
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
123
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
124
125
        self::assertEquals(2, count($result));
126
127
        self::assertArrayHasKey('user', $result[0]);
128
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
129
130
        self::assertArrayHasKey('user', $result[1]);
131
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
132
133
        self::assertEquals(1, $result[0]['user']->id);
134
        self::assertEquals('romanb', $result[0]['user']->name);
135
136
        self::assertEquals(2, $result[1]['user']->id);
137
        self::assertEquals('jwage', $result[1]['user']->name);
138
    }
139
140
    /**
141
     * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic}
142
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
143
     */
144
    public function testSimpleMultipleRootEntityQuery()
145
    {
146
        $rsm = new ResultSetMapping;
147
        $rsm->addEntityResult(CmsUser::class, 'u');
148
        $rsm->addEntityResult(CmsArticle::class, 'a');
149
        $rsm->addFieldResult('u', 'u__id', 'id');
150
        $rsm->addFieldResult('u', 'u__name', 'name');
151
        $rsm->addFieldResult('a', 'a__id', 'id');
152
        $rsm->addFieldResult('a', 'a__topic', 'topic');
153
154
        // Faked result set
155
        $resultSet = [
156
            [
157
                'u__id' => '1',
158
                'u__name' => 'romanb',
159
                'a__id' => '1',
160
                'a__topic' => 'Cool things.'
161
            ],
162
            [
163
                'u__id' => '2',
164
                'u__name' => 'jwage',
165
                'a__id' => '2',
166
                'a__topic' => 'Cool things II.'
167
            ]
168
        ];
169
170
        $stmt     = new HydratorMockStatement($resultSet);
171
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
172
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
173
174
        self::assertEquals(4, count($result));
175
176
        self::assertInstanceOf(CmsUser::class, $result[0]);
177
        self::assertInstanceOf(CmsArticle::class, $result[1]);
178
        self::assertInstanceOf(CmsUser::class, $result[2]);
179
        self::assertInstanceOf(CmsArticle::class, $result[3]);
180
181
        self::assertEquals(1, $result[0]->id);
182
        self::assertEquals('romanb', $result[0]->name);
183
184
        self::assertEquals(1, $result[1]->id);
185
        self::assertEquals('Cool things.', $result[1]->topic);
186
187
        self::assertEquals(2, $result[2]->id);
188
        self::assertEquals('jwage', $result[2]->name);
189
190
        self::assertEquals(2, $result[3]->id);
191
        self::assertEquals('Cool things II.', $result[3]->topic);
192
    }
193
194
    /**
195
     * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic}
196
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
197
     */
198 View Code Duplication
    public function testSimpleMultipleRootEntityQueryWithAliasedUserEntity()
199
    {
200
        $rsm = new ResultSetMapping;
201
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
202
        $rsm->addEntityResult(CmsArticle::class, 'a');
203
        $rsm->addFieldResult('u', 'u__id', 'id');
204
        $rsm->addFieldResult('u', 'u__name', 'name');
205
        $rsm->addFieldResult('a', 'a__id', 'id');
206
        $rsm->addFieldResult('a', 'a__topic', 'topic');
207
208
        // Faked result set
209
        $resultSet = [
210
            [
211
                'u__id' => '1',
212
                'u__name' => 'romanb',
213
                'a__id' => '1',
214
                'a__topic' => 'Cool things.'
215
            ],
216
            [
217
                'u__id' => '2',
218
                'u__name' => 'jwage',
219
                'a__id' => '2',
220
                'a__topic' => 'Cool things II.'
221
            ]
222
        ];
223
224
        $stmt     = new HydratorMockStatement($resultSet);
225
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
226
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
227
228
        self::assertEquals(4, count($result));
229
230
        self::assertArrayHasKey('user', $result[0]);
231
        self::assertArrayNotHasKey(0, $result[0]);
232
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
233
        self::assertEquals(1, $result[0]['user']->id);
234
        self::assertEquals('romanb', $result[0]['user']->name);
235
236
        self::assertArrayHasKey(0, $result[1]);
237
        self::assertArrayNotHasKey('user', $result[1]);
238
        self::assertInstanceOf(CmsArticle::class, $result[1][0]);
239
        self::assertEquals(1, $result[1][0]->id);
240
        self::assertEquals('Cool things.', $result[1][0]->topic);
241
242
        self::assertArrayHasKey('user', $result[2]);
243
        self::assertArrayNotHasKey(0, $result[2]);
244
        self::assertInstanceOf(CmsUser::class, $result[2]['user']);
245
        self::assertEquals(2, $result[2]['user']->id);
246
        self::assertEquals('jwage', $result[2]['user']->name);
247
248
        self::assertArrayHasKey(0, $result[3]);
249
        self::assertArrayNotHasKey('user', $result[3]);
250
        self::assertInstanceOf(CmsArticle::class, $result[3][0]);
251
        self::assertEquals(2, $result[3][0]->id);
252
        self::assertEquals('Cool things II.', $result[3][0]->topic);
253
    }
254
255
    /**
256
     * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} AS article
257
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
258
     */
259 View Code Duplication
    public function testSimpleMultipleRootEntityQueryWithAliasedArticleEntity()
260
    {
261
        $rsm = new ResultSetMapping;
262
        $rsm->addEntityResult(CmsUser::class, 'u');
263
        $rsm->addEntityResult(CmsArticle::class, 'a', 'article');
264
        $rsm->addFieldResult('u', 'u__id', 'id');
265
        $rsm->addFieldResult('u', 'u__name', 'name');
266
        $rsm->addFieldResult('a', 'a__id', 'id');
267
        $rsm->addFieldResult('a', 'a__topic', 'topic');
268
269
        // Faked result set
270
        $resultSet = [
271
            [
272
                'u__id' => '1',
273
                'u__name' => 'romanb',
274
                'a__id' => '1',
275
                'a__topic' => 'Cool things.'
276
            ],
277
            [
278
                'u__id' => '2',
279
                'u__name' => 'jwage',
280
                'a__id' => '2',
281
                'a__topic' => 'Cool things II.'
282
            ]
283
        ];
284
285
        $stmt     = new HydratorMockStatement($resultSet);
286
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
287
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
288
289
        self::assertEquals(4, count($result));
290
291
        self::assertArrayHasKey(0, $result[0]);
292
        self::assertArrayNotHasKey('article', $result[0]);
293
        self::assertInstanceOf(CmsUser::class, $result[0][0]);
294
        self::assertEquals(1, $result[0][0]->id);
295
        self::assertEquals('romanb', $result[0][0]->name);
296
297
        self::assertArrayHasKey('article', $result[1]);
298
        self::assertArrayNotHasKey(0, $result[1]);
299
        self::assertInstanceOf(CmsArticle::class, $result[1]['article']);
300
        self::assertEquals(1, $result[1]['article']->id);
301
        self::assertEquals('Cool things.', $result[1]['article']->topic);
302
303
        self::assertArrayHasKey(0, $result[2]);
304
        self::assertArrayNotHasKey('article', $result[2]);
305
        self::assertInstanceOf(CmsUser::class, $result[2][0]);
306
        self::assertEquals(2, $result[2][0]->id);
307
        self::assertEquals('jwage', $result[2][0]->name);
308
309
        self::assertArrayHasKey('article', $result[3]);
310
        self::assertArrayNotHasKey(0, $result[3]);
311
        self::assertInstanceOf(CmsArticle::class, $result[3]['article']);
312
        self::assertEquals(2, $result[3]['article']->id);
313
        self::assertEquals('Cool things II.', $result[3]['article']->topic);
314
    }
315
316
    /**
317
     * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} AS article
318
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
319
     */
320 View Code Duplication
    public function testSimpleMultipleRootEntityQueryWithAliasedEntities()
321
    {
322
        $rsm = new ResultSetMapping;
323
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
324
        $rsm->addEntityResult(CmsArticle::class, 'a', 'article');
325
        $rsm->addFieldResult('u', 'u__id', 'id');
326
        $rsm->addFieldResult('u', 'u__name', 'name');
327
        $rsm->addFieldResult('a', 'a__id', 'id');
328
        $rsm->addFieldResult('a', 'a__topic', 'topic');
329
330
        // Faked result set
331
        $resultSet = [
332
            [
333
                'u__id' => '1',
334
                'u__name' => 'romanb',
335
                'a__id' => '1',
336
                'a__topic' => 'Cool things.'
337
            ],
338
            [
339
                'u__id' => '2',
340
                'u__name' => 'jwage',
341
                'a__id' => '2',
342
                'a__topic' => 'Cool things II.'
343
            ]
344
        ];
345
346
        $stmt     = new HydratorMockStatement($resultSet);
347
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
348
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
349
350
        self::assertEquals(4, count($result));
351
352
        self::assertArrayHasKey('user', $result[0]);
353
        self::assertArrayNotHasKey('article', $result[0]);
354
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
355
        self::assertEquals(1, $result[0]['user']->id);
356
        self::assertEquals('romanb', $result[0]['user']->name);
357
358
        self::assertArrayHasKey('article', $result[1]);
359
        self::assertArrayNotHasKey('user', $result[1]);
360
        self::assertInstanceOf(CmsArticle::class, $result[1]['article']);
361
        self::assertEquals(1, $result[1]['article']->id);
362
        self::assertEquals('Cool things.', $result[1]['article']->topic);
363
364
        self::assertArrayHasKey('user', $result[2]);
365
        self::assertArrayNotHasKey('article', $result[2]);
366
        self::assertInstanceOf(CmsUser::class, $result[2]['user']);
367
        self::assertEquals(2, $result[2]['user']->id);
368
        self::assertEquals('jwage', $result[2]['user']->name);
369
370
        self::assertArrayHasKey('article', $result[3]);
371
        self::assertArrayNotHasKey('user', $result[3]);
372
        self::assertInstanceOf(CmsArticle::class, $result[3]['article']);
373
        self::assertEquals(2, $result[3]['article']->id);
374
        self::assertEquals('Cool things II.', $result[3]['article']->topic);
375
    }
376
377
    /**
378
     * SELECT PARTIAL u.{id, status}, COUNT(p.phonenumber) numPhones
379
     *   FROM User u
380
     *   JOIN u.phonenumbers p
381
     *  GROUP BY u.id
382
     *
383
     * @dataProvider provideDataForUserEntityResult
384
     */
385
    public function testMixedQueryNormalJoin($userEntityKey)
386
    {
387
        $rsm = new ResultSetMapping;
388
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
389
        $rsm->addFieldResult('u', 'u__id', 'id');
390
        $rsm->addFieldResult('u', 'u__status', 'status');
391
        $rsm->addScalarResult('sclr0', 'numPhones', Type::getType('integer'));
392
393
        // Faked result set
394
        $resultSet = [
395
            //row1
396
            [
397
                'u__id' => '1',
398
                'u__status' => 'developer',
399
                'sclr0' => '2',
400
            ],
401
            [
402
                'u__id' => '2',
403
                'u__status' => 'developer',
404
                'sclr0' => '1',
405
            ]
406
        ];
407
408
        $stmt     = new HydratorMockStatement($resultSet);
409
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
410
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
411
412
        self::assertEquals(2, count($result));
413
414
        self::assertInternalType('array', $result);
415
        self::assertInternalType('array', $result[0]);
416
        self::assertInternalType('array', $result[1]);
417
418
        // first user => 2 phonenumbers
419
        self::assertEquals(2, $result[0]['numPhones']);
420
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
421
422
        // second user => 1 phonenumber
423
        self::assertEquals(1, $result[1]['numPhones']);
424
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
425
    }
426
427
    /**
428
     * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) nameUpper
429
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
430
     *   JOIN u.phonenumbers p
431
     *
432
     * @dataProvider provideDataForUserEntityResult
433
     */
434
    public function testMixedQueryFetchJoin($userEntityKey)
435
    {
436
        $rsm = new ResultSetMapping;
437
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
438
        $rsm->addJoinedEntityResult(
439
            CmsPhonenumber::class,
440
            'p',
441
            'u',
442
            'phonenumbers'
443
        );
444
        $rsm->addFieldResult('u', 'u__id', 'id');
445
        $rsm->addFieldResult('u', 'u__status', 'status');
446
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
447
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
448
449
        // Faked result set
450
        $resultSet = [
451
            //row1
452
            [
453
                'u__id' => '1',
454
                'u__status' => 'developer',
455
                'p__phonenumber' => '42',
456
                'sclr0' => 'ROMANB',
457
            ],
458
            [
459
                'u__id' => '1',
460
                'u__status' => 'developer',
461
                'p__phonenumber' => '43',
462
                'sclr0' => 'ROMANB',
463
            ],
464
            [
465
                'u__id' => '2',
466
                'u__status' => 'developer',
467
                'p__phonenumber' => '91',
468
                'sclr0' => 'JWAGE',
469
            ]
470
        ];
471
472
        $stmt     = new HydratorMockStatement($resultSet);
473
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
474
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
475
476
        self::assertEquals(2, count($result));
477
478
        self::assertInternalType('array', $result);
479
        self::assertInternalType('array', $result[0]);
480
        self::assertInternalType('array', $result[1]);
481
482
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
483
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
484
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
485
486
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
487
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
488
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
489
490
        // first user => 2 phonenumbers
491
        self::assertEquals(2, count($result[0][$userEntityKey]->phonenumbers));
492
        self::assertEquals('ROMANB', $result[0]['nameUpper']);
493
494
        // second user => 1 phonenumber
495
        self::assertEquals(1, count($result[1][$userEntityKey]->phonenumbers));
496
        self::assertEquals('JWAGE', $result[1]['nameUpper']);
497
498
        self::assertEquals(42, $result[0][$userEntityKey]->phonenumbers[0]->phonenumber);
499
        self::assertEquals(43, $result[0][$userEntityKey]->phonenumbers[1]->phonenumber);
500
        self::assertEquals(91, $result[1][$userEntityKey]->phonenumbers[0]->phonenumber);
501
    }
502
503
    /**
504
     * SELECT u, p, UPPER(u.name) nameUpper
505
     *   FROM User u
506
     *        INDEX BY u.id
507
     *   JOIN u.phonenumbers p
508
     *        INDEX BY p.phonenumber
509
     *
510
     * @dataProvider provideDataForUserEntityResult
511
     */
512
    public function testMixedQueryFetchJoinCustomIndex($userEntityKey)
513
    {
514
        $rsm = new ResultSetMapping;
515
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
516
        $rsm->addJoinedEntityResult(
517
            CmsPhonenumber::class,
518
            'p',
519
            'u',
520
            'phonenumbers'
521
        );
522
        $rsm->addFieldResult('u', 'u__id', 'id');
523
        $rsm->addFieldResult('u', 'u__status', 'status');
524
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
525
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
526
        $rsm->addIndexBy('u', 'id');
527
        $rsm->addIndexBy('p', 'phonenumber');
528
529
        // Faked result set
530
        $resultSet = [
531
            //row1
532
            [
533
                'u__id' => '1',
534
                'u__status' => 'developer',
535
                'sclr0' => 'ROMANB',
536
                'p__phonenumber' => '42',
537
            ],
538
            [
539
                'u__id' => '1',
540
                'u__status' => 'developer',
541
                'sclr0' => 'ROMANB',
542
                'p__phonenumber' => '43',
543
            ],
544
            [
545
                'u__id' => '2',
546
                'u__status' => 'developer',
547
                'sclr0' => 'JWAGE',
548
                'p__phonenumber' => '91'
549
            ]
550
        ];
551
552
553
        $stmt     = new HydratorMockStatement($resultSet);
554
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
555
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
556
557
        self::assertEquals(2, count($result));
558
559
        self::assertInternalType('array', $result);
560
        self::assertInternalType('array', $result[1]);
561
        self::assertInternalType('array', $result[2]);
562
563
        // test the scalar values
564
        self::assertEquals('ROMANB', $result[1]['nameUpper']);
565
        self::assertEquals('JWAGE', $result[2]['nameUpper']);
566
567
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
568
        self::assertInstanceOf(CmsUser::class, $result[2][$userEntityKey]);
569
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
570
571
        // first user => 2 phonenumbers. notice the custom indexing by user id
572
        self::assertEquals(2, count($result[1][$userEntityKey]->phonenumbers));
573
574
        // second user => 1 phonenumber. notice the custom indexing by user id
575
        self::assertEquals(1, count($result[2][$userEntityKey]->phonenumbers));
576
577
        // test the custom indexing of the phonenumbers
578
        self::assertTrue(isset($result[1][$userEntityKey]->phonenumbers['42']));
579
        self::assertTrue(isset($result[1][$userEntityKey]->phonenumbers['43']));
580
        self::assertTrue(isset($result[2][$userEntityKey]->phonenumbers['91']));
581
    }
582
583
    /**
584
     * SELECT u, p, UPPER(u.name) nameUpper, a
585
     *   FROM User u
586
     *   JOIN u.phonenumbers p
587
     *   JOIN u.articles a
588
     *
589
     * @dataProvider provideDataForUserEntityResult
590
     */
591
    public function testMixedQueryMultipleFetchJoin($userEntityKey)
592
    {
593
        $rsm = new ResultSetMapping;
594
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
595
        $rsm->addJoinedEntityResult(
596
            CmsPhonenumber::class,
597
            'p',
598
            'u',
599
            'phonenumbers'
600
        );
601
        $rsm->addJoinedEntityResult(
602
            CmsArticle::class,
603
            'a',
604
            'u',
605
            'articles'
606
        );
607
        $rsm->addFieldResult('u', 'u__id', 'id');
608
        $rsm->addFieldResult('u', 'u__status', 'status');
609
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
610
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
611
        $rsm->addFieldResult('a', 'a__id', 'id');
612
        $rsm->addFieldResult('a', 'a__topic', 'topic');
613
614
        // Faked result set
615
        $resultSet = [
616
            //row1
617
            [
618
                'u__id' => '1',
619
                'u__status' => 'developer',
620
                'sclr0' => 'ROMANB',
621
                'p__phonenumber' => '42',
622
                'a__id' => '1',
623
                'a__topic' => 'Getting things done!'
624
            ],
625
            [
626
                'u__id' => '1',
627
                'u__status' => 'developer',
628
                'sclr0' => 'ROMANB',
629
                'p__phonenumber' => '43',
630
                'a__id' => '1',
631
                'a__topic' => 'Getting things done!'
632
            ],
633
            [
634
                'u__id' => '1',
635
                'u__status' => 'developer',
636
                'sclr0' => 'ROMANB',
637
                'p__phonenumber' => '42',
638
                'a__id' => '2',
639
                'a__topic' => 'ZendCon'
640
            ],
641
            [
642
                'u__id' => '1',
643
                'u__status' => 'developer',
644
                'sclr0' => 'ROMANB',
645
                'p__phonenumber' => '43',
646
                'a__id' => '2',
647
                'a__topic' => 'ZendCon'
648
            ],
649
            [
650
                'u__id' => '2',
651
                'u__status' => 'developer',
652
                'sclr0' => 'JWAGE',
653
                'p__phonenumber' => '91',
654
                'a__id' => '3',
655
                'a__topic' => 'LINQ'
656
            ],
657
            [
658
                'u__id' => '2',
659
                'u__status' => 'developer',
660
                'sclr0' => 'JWAGE',
661
                'p__phonenumber' => '91',
662
                'a__id' => '4',
663
                'a__topic' => 'PHP7'
664
            ],
665
        ];
666
667
        $stmt     = new HydratorMockStatement($resultSet);
668
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
669
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
670
671
        self::assertEquals(2, count($result));
672
673
        self::assertTrue(is_array($result));
674
        self::assertTrue(is_array($result[0]));
675
        self::assertTrue(is_array($result[1]));
676
677
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
678
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
679
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
680
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
681
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles);
682
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[0]);
683
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[1]);
684
685
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
686
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
687
        self::assertInstanceOf(CmsPhonenumber::class, $result[1][$userEntityKey]->phonenumbers[0]);
688
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[0]);
689
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[1]);
690
    }
691
692
    /**
693
     * SELECT u, p, UPPER(u.name) nameUpper, a, c
694
     *   FROM User u
695
     *   JOIN u.phonenumbers p
696
     *   JOIN u.articles a
697
     *   LEFT JOIN a.comments c
698
     *
699
     * @dataProvider provideDataForUserEntityResult
700
     */
701
    public function testMixedQueryMultipleDeepMixedFetchJoin($userEntityKey)
702
    {
703
        $rsm = new ResultSetMapping;
704
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
705
        $rsm->addJoinedEntityResult(
706
            CmsPhonenumber::class,
707
            'p',
708
            'u',
709
            'phonenumbers'
710
        );
711
        $rsm->addJoinedEntityResult(
712
            CmsArticle::class,
713
            'a',
714
            'u',
715
            'articles'
716
        );
717
        $rsm->addJoinedEntityResult(
718
            CmsComment::class,
719
            'c',
720
            'a',
721
            'comments'
722
        );
723
        $rsm->addFieldResult('u', 'u__id', 'id');
724
        $rsm->addFieldResult('u', 'u__status', 'status');
725
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
726
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
727
        $rsm->addFieldResult('a', 'a__id', 'id');
728
        $rsm->addFieldResult('a', 'a__topic', 'topic');
729
        $rsm->addFieldResult('c', 'c__id', 'id');
730
        $rsm->addFieldResult('c', 'c__topic', 'topic');
731
732
        // Faked result set
733
        $resultSet = [
734
            //row1
735
            [
736
                'u__id' => '1',
737
                'u__status' => 'developer',
738
                'sclr0' => 'ROMANB',
739
                'p__phonenumber' => '42',
740
                'a__id' => '1',
741
                'a__topic' => 'Getting things done!',
742
                'c__id' => '1',
743
                'c__topic' => 'First!'
744
            ],
745
            [
746
                'u__id' => '1',
747
                'u__status' => 'developer',
748
                'sclr0' => 'ROMANB',
749
                'p__phonenumber' => '43',
750
                'a__id' => '1',
751
                'a__topic' => 'Getting things done!',
752
                'c__id' => '1',
753
                'c__topic' => 'First!'
754
            ],
755
            [
756
                'u__id' => '1',
757
                'u__status' => 'developer',
758
                'sclr0' => 'ROMANB',
759
                'p__phonenumber' => '42',
760
                'a__id' => '2',
761
                'a__topic' => 'ZendCon',
762
                'c__id' => null,
763
                'c__topic' => null
764
            ],
765
            [
766
                'u__id' => '1',
767
                'u__status' => 'developer',
768
                'sclr0' => 'ROMANB',
769
                'p__phonenumber' => '43',
770
                'a__id' => '2',
771
                'a__topic' => 'ZendCon',
772
                'c__id' => null,
773
                'c__topic' => null
774
            ],
775
            [
776
                'u__id' => '2',
777
                'u__status' => 'developer',
778
                'sclr0' => 'JWAGE',
779
                'p__phonenumber' => '91',
780
                'a__id' => '3',
781
                'a__topic' => 'LINQ',
782
                'c__id' => null,
783
                'c__topic' => null
784
            ],
785
            [
786
                'u__id' => '2',
787
                'u__status' => 'developer',
788
                'sclr0' => 'JWAGE',
789
                'p__phonenumber' => '91',
790
                'a__id' => '4',
791
                'a__topic' => 'PHP7',
792
                'c__id' => null,
793
                'c__topic' => null
794
            ],
795
        ];
796
797
        $stmt     = new HydratorMockStatement($resultSet);
798
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
799
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
800
801
        self::assertEquals(2, count($result));
802
803
        self::assertTrue(is_array($result));
804
        self::assertTrue(is_array($result[0]));
805
        self::assertTrue(is_array($result[1]));
806
807
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
808
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
809
810
        // phonenumbers
811
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
812
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
813
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
814
815
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
816
        self::assertInstanceOf(CmsPhonenumber::class, $result[1][$userEntityKey]->phonenumbers[0]);
817
818
        // articles
819
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles);
820
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[0]);
821
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[1]);
822
823
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[0]);
824
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[1]);
825
826
        // article comments
827
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles[0]->comments);
828
        self::assertInstanceOf(CmsComment::class, $result[0][$userEntityKey]->articles[0]->comments[0]);
829
830
        // empty comment collections
831
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles[1]->comments);
832
        self::assertEquals(0, count($result[0][$userEntityKey]->articles[1]->comments));
833
834
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->articles[0]->comments);
835
        self::assertEquals(0, count($result[1][$userEntityKey]->articles[0]->comments));
836
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->articles[1]->comments);
837
        self::assertEquals(0, count($result[1][$userEntityKey]->articles[1]->comments));
838
    }
839
840
    /**
841
     * Tests that the hydrator does not rely on a particular order of the rows
842
     * in the result set.
843
     *
844
     * DQL:
845
     * select c, b from Doctrine\Tests\Models\Forum\ForumCategory c inner join c.boards b
846
     * order by c.position asc, b.position asc
847
     *
848
     * Checks whether the boards are correctly assigned to the categories.
849
     *
850
     * The 'evil' result set that confuses the object population is displayed below.
851
     *
852
     * c.id  | c.position | c.name   | boardPos | b.id | b.category_id (just for clarity)
853
     *  1    | 0          | First    | 0        |   1  | 1
854
     *  2    | 0          | Second   | 0        |   2  | 2   <--
855
     *  1    | 0          | First    | 1        |   3  | 1
856
     *  1    | 0          | First    | 2        |   4  | 1
857
     */
858
    public function testEntityQueryCustomResultSetOrder()
859
    {
860
        $rsm = new ResultSetMapping;
861
        $rsm->addEntityResult(ForumCategory::class, 'c');
862
        $rsm->addJoinedEntityResult(
863
            ForumBoard::class,
864
            'b',
865
            'c',
866
            'boards'
867
        );
868
        $rsm->addFieldResult('c', 'c__id', 'id');
869
        $rsm->addFieldResult('c', 'c__position', 'position');
870
        $rsm->addFieldResult('c', 'c__name', 'name');
871
        $rsm->addFieldResult('b', 'b__id', 'id');
872
        $rsm->addFieldResult('b', 'b__position', 'position');
873
874
        // Faked result set
875
        $resultSet = [
876
            [
877
                'c__id' => '1',
878
                'c__position' => '0',
879
                'c__name' => 'First',
880
                'b__id' => '1',
881
                'b__position' => '0',
882
                //'b__category_id' => '1'
883
            ],
884
            [
885
                'c__id' => '2',
886
                'c__position' => '0',
887
                'c__name' => 'Second',
888
                'b__id' => '2',
889
                'b__position' => '0',
890
                //'b__category_id' => '2'
891
            ],
892
            [
893
                'c__id' => '1',
894
                'c__position' => '0',
895
                'c__name' => 'First',
896
                'b__id' => '3',
897
                'b__position' => '1',
898
                //'b__category_id' => '1'
899
            ],
900
            [
901
                'c__id' => '1',
902
                'c__position' => '0',
903
                'c__name' => 'First',
904
                'b__id' => '4',
905
                'b__position' => '2',
906
                //'b__category_id' => '1'
907
            ]
908
        ];
909
910
        $stmt     = new HydratorMockStatement($resultSet);
911
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
912
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
913
914
        self::assertEquals(2, count($result));
915
916
        self::assertInstanceOf(ForumCategory::class, $result[0]);
917
        self::assertInstanceOf(ForumCategory::class, $result[1]);
918
919
        self::assertTrue($result[0] !== $result[1]);
920
921
        self::assertEquals(1, $result[0]->getId());
922
        self::assertEquals(2, $result[1]->getId());
923
924
        self::assertTrue(isset($result[0]->boards));
925
        self::assertEquals(3, count($result[0]->boards));
926
927
        self::assertTrue(isset($result[1]->boards));
928
        self::assertEquals(1, count($result[1]->boards));
929
    }
930
931
    /**
932
     * SELECT PARTIAL u.{id,name}
933
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
934
     *
935
     * @group DDC-644
936
     */
937
    public function testSkipUnknownColumns()
938
    {
939
        $rsm = new ResultSetMapping;
940
        $rsm->addEntityResult(CmsUser::class, 'u');
941
        $rsm->addFieldResult('u', 'u__id', 'id');
942
        $rsm->addFieldResult('u', 'u__name', 'name');
943
944
        // Faked result set
945
        $resultSet = [
946
            [
947
                'u__id' => '1',
948
                'u__name' => 'romanb',
949
                'foo' => 'bar', // unknown!
950
            ],
951
        ];
952
953
        $stmt     = new HydratorMockStatement($resultSet);
954
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
955
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
956
957
        self::assertEquals(1, count($result));
958
        self::assertInstanceOf(CmsUser::class, $result[0]);
959
    }
960
961
    /**
962
     * SELECT u.id, u.name
963
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
964
     *
965
     * @dataProvider provideDataForUserEntityResult
966
     */
967
    public function testScalarQueryWithoutResultVariables($userEntityKey)
968
    {
969
        $rsm = new ResultSetMapping;
970
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
971
        $rsm->addScalarResult('sclr0', 'id', Type::getType('integer'));
972
        $rsm->addScalarResult('sclr1', 'name', Type::getType('string'));
973
974
        // Faked result set
975
        $resultSet = [
976
            [
977
                'sclr0' => '1',
978
                'sclr1' => 'romanb'
979
            ],
980
            [
981
                'sclr0' => '2',
982
                'sclr1' => 'jwage'
983
            ]
984
        ];
985
986
        $stmt     = new HydratorMockStatement($resultSet);
987
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
988
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
989
990
        self::assertEquals(2, count($result));
991
992
        self::assertInternalType('array', $result[0]);
993
        self::assertInternalType('array', $result[1]);
994
995
        self::assertEquals(1, $result[0]['id']);
996
        self::assertEquals('romanb', $result[0]['name']);
997
998
        self::assertEquals(2, $result[1]['id']);
999
        self::assertEquals('jwage', $result[1]['name']);
1000
    }
1001
1002
    /**
1003
     * SELECT p
1004
     *   FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p
1005
     */
1006
    public function testCreatesProxyForLazyLoadingWithForeignKeys()
1007
    {
1008
        $rsm = new ResultSetMapping;
1009
        $rsm->addEntityResult(ECommerceProduct::class, 'p');
1010
        $rsm->addFieldResult('p', 'p__id', 'id');
1011
        $rsm->addFieldResult('p', 'p__name', 'name');
1012
        $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id', false, Type::getType('integer'));
1013
1014
        // Faked result set
1015
        $resultSet = [
1016
            [
1017
                'p__id' => '1',
1018
                'p__name' => 'Doctrine Book',
1019
                'p__shipping_id' => 42
1020
            ]
1021
        ];
1022
1023
        $proxyInstance = new \Doctrine\Tests\Models\ECommerce\ECommerceShipping();
1024
1025
        // mocking the proxy factory
1026
        $proxyFactory = $this->getMockBuilder(ProxyFactory::class)
1027
                             ->setMethods(['getProxy'])
1028
                             ->disableOriginalConstructor()
1029
                             ->getMock();
1030
1031
        $proxyFactory->expects($this->once())
1032
                     ->method('getProxy')
1033
                     ->with($this->equalTo(ECommerceShipping::class), ['id' => 42])
1034
                     ->will($this->returnValue($proxyInstance));
1035
1036
        // @todo guilhermeblanco This should never have happened... replace this Reflection injection with proper API.
1037
        $this->swapPrivateProperty($this->em, 'proxyFactory', $proxyFactory);
1038
1039
        // configuring lazy loading
1040
        $metadata = $this->em->getClassMetadata(ECommerceProduct::class);
1041
        $metadata->getProperty('shipping')->setFetchMode(FetchMode::LAZY);
0 ignored issues
show
Bug introduced by
The method getProperty() does not seem to exist on object<Doctrine\Common\P...\Mapping\ClassMetadata>.

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...
1042
1043
        $stmt     = new HydratorMockStatement($resultSet);
1044
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1045
        $result   = $hydrator->hydrateAll($stmt, $rsm);
1046
1047
        self::assertEquals(1, count($result));
1048
1049
        self::assertInstanceOf(ECommerceProduct::class, $result[0]);
1050
    }
1051
1052
    /**
1053
     * SELECT p AS product
1054
     *   FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p
1055
     */
1056
    public function testCreatesProxyForLazyLoadingWithForeignKeysWithAliasedProductEntity()
1057
    {
1058
        $rsm = new ResultSetMapping;
1059
        $rsm->addEntityResult(ECommerceProduct::class, 'p', 'product');
1060
        $rsm->addFieldResult('p', 'p__id', 'id');
1061
        $rsm->addFieldResult('p', 'p__name', 'name');
1062
        $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id', false, Type::getType('integer'));
1063
1064
        // Faked result set
1065
        $resultSet = [
1066
            [
1067
                'p__id' => '1',
1068
                'p__name' => 'Doctrine Book',
1069
                'p__shipping_id' => 42
1070
            ]
1071
        ];
1072
1073
        $proxyInstance = new \Doctrine\Tests\Models\ECommerce\ECommerceShipping();
1074
1075
        // mocking the proxy factory
1076
        $proxyFactory = $this->getMockBuilder(ProxyFactory::class)
1077
                             ->setMethods(['getProxy'])
1078
                             ->disableOriginalConstructor()
1079
                             ->getMock();
1080
1081
        $proxyFactory->expects($this->once())
1082
                     ->method('getProxy')
1083
                     ->with($this->equalTo(ECommerceShipping::class), ['id' => 42])
1084
                     ->will($this->returnValue($proxyInstance));
1085
1086
        // @todo guilhermeblanco This should never have happened... replace this Reflection injection with proper API.
1087
        $this->swapPrivateProperty($this->em, 'proxyFactory', $proxyFactory);
1088
1089
        // configuring lazy loading
1090
        $metadata = $this->em->getClassMetadata(ECommerceProduct::class);
1091
        $metadata->getProperty('shipping')->setFetchMode(FetchMode::LAZY);
0 ignored issues
show
Bug introduced by
The method getProperty() does not seem to exist on object<Doctrine\Common\P...\Mapping\ClassMetadata>.

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...
1092
1093
        $stmt     = new HydratorMockStatement($resultSet);
1094
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1095
        $result   = $hydrator->hydrateAll($stmt, $rsm);
1096
1097
        self::assertEquals(1, count($result));
1098
1099
        self::assertInternalType('array', $result[0]);
1100
        self::assertInstanceOf(ECommerceProduct::class, $result[0]['product']);
1101
    }
1102
1103
    /**
1104
     * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, topic}, PARTIAL c.{id, topic}
1105
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1106
     *   LEFT JOIN u.articles a
1107
     *   LEFT JOIN a.comments c
1108
     */
1109
    public function testChainedJoinWithEmptyCollections()
1110
    {
1111
        $rsm = new ResultSetMapping;
1112
        $rsm->addEntityResult(CmsUser::class, 'u');
1113
        $rsm->addJoinedEntityResult(
1114
            CmsArticle::class,
1115
            'a',
1116
            'u',
1117
            'articles'
1118
        );
1119
        $rsm->addJoinedEntityResult(
1120
            CmsComment::class,
1121
            'c',
1122
            'a',
1123
            'comments'
1124
        );
1125
        $rsm->addFieldResult('u', 'u__id', 'id');
1126
        $rsm->addFieldResult('u', 'u__status', 'status');
1127
        $rsm->addFieldResult('a', 'a__id', 'id');
1128
        $rsm->addFieldResult('a', 'a__topic', 'topic');
1129
        $rsm->addFieldResult('c', 'c__id', 'id');
1130
        $rsm->addFieldResult('c', 'c__topic', 'topic');
1131
1132
        // Faked result set
1133
        $resultSet = [
1134
            //row1
1135
            [
1136
                'u__id' => '1',
1137
                'u__status' => 'developer',
1138
                'a__id' => null,
1139
                'a__topic' => null,
1140
                'c__id' => null,
1141
                'c__topic' => null
1142
            ],
1143
            [
1144
                'u__id' => '2',
1145
                'u__status' => 'developer',
1146
                'a__id' => null,
1147
                'a__topic' => null,
1148
                'c__id' => null,
1149
                'c__topic' => null
1150
            ],
1151
        ];
1152
1153
        $stmt     = new HydratorMockStatement($resultSet);
1154
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1155
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1156
1157
        self::assertEquals(2, count($result));
1158
1159
        self::assertInstanceOf(CmsUser::class, $result[0]);
1160
        self::assertInstanceOf(CmsUser::class, $result[1]);
1161
1162
        self::assertEquals(0, $result[0]->articles->count());
1163
        self::assertEquals(0, $result[1]->articles->count());
1164
    }
1165
1166
    /**
1167
     * SELECT PARTIAL u.{id, status} AS user, PARTIAL a.{id, topic}, PARTIAL c.{id, topic}
1168
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1169
     *   LEFT JOIN u.articles a
1170
     *   LEFT JOIN a.comments c
1171
     */
1172
    public function testChainedJoinWithEmptyCollectionsWithAliasedUserEntity()
1173
    {
1174
        $rsm = new ResultSetMapping;
1175
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1176
        $rsm->addJoinedEntityResult(
1177
            CmsArticle::class,
1178
            'a',
1179
            'u',
1180
            'articles'
1181
        );
1182
        $rsm->addJoinedEntityResult(
1183
            CmsComment::class,
1184
            'c',
1185
            'a',
1186
            'comments'
1187
        );
1188
        $rsm->addFieldResult('u', 'u__id', 'id');
1189
        $rsm->addFieldResult('u', 'u__status', 'status');
1190
        $rsm->addFieldResult('a', 'a__id', 'id');
1191
        $rsm->addFieldResult('a', 'a__topic', 'topic');
1192
        $rsm->addFieldResult('c', 'c__id', 'id');
1193
        $rsm->addFieldResult('c', 'c__topic', 'topic');
1194
1195
        // Faked result set
1196
        $resultSet = [
1197
            //row1
1198
            [
1199
                'u__id' => '1',
1200
                'u__status' => 'developer',
1201
                'a__id' => null,
1202
                'a__topic' => null,
1203
                'c__id' => null,
1204
                'c__topic' => null
1205
            ],
1206
            [
1207
                'u__id' => '2',
1208
                'u__status' => 'developer',
1209
                'a__id' => null,
1210
                'a__topic' => null,
1211
                'c__id' => null,
1212
                'c__topic' => null
1213
            ],
1214
        ];
1215
1216
        $stmt     = new HydratorMockStatement($resultSet);
1217
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1218
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1219
1220
        self::assertEquals(2, count($result));
1221
1222
        self::assertInternalType('array', $result[0]);
1223
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1224
1225
        self::assertInternalType('array', $result[1]);
1226
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
1227
1228
        self::assertEquals(0, $result[0]['user']->articles->count());
1229
        self::assertEquals(0, $result[1]['user']->articles->count());
1230
    }
1231
1232
    /**
1233
     * SELECT PARTIAL u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic
1234
     *   FROM CmsUser u
1235
     *   LEFT JOIN u.articles a
1236
     *   LEFT JOIN a.comments c
1237
     *
1238
     * @todo Figure it out why this test is commented out and provide a better description in docblock
1239
     *
1240
     * @group bubu
1241
     * @dataProvider provideDataForUserEntityResult
1242
     */
1243
    /*public function testChainedJoinWithScalars($userEntityKey)
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% 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...
1244
    {
1245
        $rsm = new ResultSetMapping;
1246
        $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
1247
        $rsm->addFieldResult('u', 'u__id', 'id');
1248
        $rsm->addFieldResult('u', 'u__status', 'status');
1249
        $rsm->addScalarResult('a__id', 'id', Type::getType('integer'));
1250
        $rsm->addScalarResult('a__topic', 'topic', Type::getType('string'));
1251
        $rsm->addScalarResult('c__id', 'cid', Type::getType('integer'));
1252
        $rsm->addScalarResult('c__topic', 'ctopic', Type::getType('string'));
1253
1254
        // Faked result set
1255
        $resultSet = array(
1256
            //row1
1257
            array(
1258
                'u__id' => '1',
1259
                'u__status' => 'developer',
1260
                'a__id' => '1',
1261
                'a__topic' => 'The First',
1262
                'c__id' => '1',
1263
                'c__topic' => 'First Comment'
1264
            ),
1265
            array(
1266
                'u__id' => '1',
1267
                'u__status' => 'developer',
1268
                'a__id' => '1',
1269
                'a__topic' => 'The First',
1270
                'c__id' => '2',
1271
                'c__topic' => 'Second Comment'
1272
            ),
1273
            array(
1274
                'u__id' => '1',
1275
                'u__status' => 'developer',
1276
                'a__id' => '42',
1277
                'a__topic' => 'The Answer',
1278
                'c__id' => null,
1279
                'c__topic' => null
1280
            ),
1281
        );
1282
1283
        $stmt     = new HydratorMockStatement($resultSet);
1284
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1285
        $result   = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
1286
1287
        \Doctrine\Common\Util\Debug::dump($result, 3);
1288
1289
        self::assertEquals(1, count($result));
1290
1291
        self::assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); // User object
1292
        self::assertEquals(42, $result[0]['id']);
1293
        self::assertEquals('The First', $result[0]['topic']);
1294
        self::assertEquals(1, $result[0]['cid']);
1295
        self::assertEquals('First Comment', $result[0]['ctopic']);
1296
    }*/
1297
1298
    /**
1299
     * SELECT PARTIAL u.{id, name}
1300
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1301
     */
1302
    public function testResultIteration()
1303
    {
1304
        $rsm = new ResultSetMapping;
1305
        $rsm->addEntityResult(CmsUser::class, 'u');
1306
        $rsm->addFieldResult('u', 'u__id', 'id');
1307
        $rsm->addFieldResult('u', 'u__name', 'name');
1308
1309
        // Faked result set
1310
        $resultSet = [
1311
            [
1312
                'u__id' => '1',
1313
                'u__name' => 'romanb'
1314
            ],
1315
            [
1316
                'u__id' => '2',
1317
                'u__name' => 'jwage'
1318
            ]
1319
        ];
1320
1321
        $stmt           = new HydratorMockStatement($resultSet);
1322
        $hydrator       = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1323
        $iterableResult = $hydrator->iterate($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1324
        $rowNum         = 0;
1325
1326
        while (($row = $iterableResult->next()) !== false) {
1327
            self::assertEquals(1, count($row));
1328
            self::assertInstanceOf(CmsUser::class, $row[0]);
1329
1330
            if ($rowNum == 0) {
1331
                self::assertEquals(1, $row[0]->id);
1332
                self::assertEquals('romanb', $row[0]->name);
1333 View Code Duplication
            } else if ($rowNum == 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1334
                self::assertEquals(2, $row[0]->id);
1335
                self::assertEquals('jwage', $row[0]->name);
1336
            }
1337
1338
            ++$rowNum;
1339
        }
1340
    }
1341
1342
    /**
1343
     * SELECT PARTIAL u.{id, name}
1344
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1345
     */
1346
    public function testResultIterationWithAliasedUserEntity()
1347
    {
1348
        $rsm = new ResultSetMapping;
1349
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1350
        $rsm->addFieldResult('u', 'u__id', 'id');
1351
        $rsm->addFieldResult('u', 'u__name', 'name');
1352
1353
        // Faked result set
1354
        $resultSet = [
1355
            [
1356
                'u__id' => '1',
1357
                'u__name' => 'romanb'
1358
            ],
1359
            [
1360
                'u__id' => '2',
1361
                'u__name' => 'jwage'
1362
            ]
1363
        ];
1364
1365
        $stmt           = new HydratorMockStatement($resultSet);
1366
        $hydrator       = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1367
        $iterableResult = $hydrator->iterate($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1368
        $rowNum         = 0;
1369
1370
        while (($row = $iterableResult->next()) !== false) {
1371
            self::assertEquals(1, count($row));
1372
            self::assertArrayHasKey(0, $row);
1373
            self::assertArrayHasKey('user', $row[0]);
1374
            self::assertInstanceOf(CmsUser::class, $row[0]['user']);
1375
1376
            if ($rowNum == 0) {
1377
                self::assertEquals(1, $row[0]['user']->id);
1378
                self::assertEquals('romanb', $row[0]['user']->name);
1379 View Code Duplication
            } else if ($rowNum == 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1380
                self::assertEquals(2, $row[0]['user']->id);
1381
                self::assertEquals('jwage', $row[0]['user']->name);
1382
            }
1383
1384
            ++$rowNum;
1385
        }
1386
    }
1387
1388
    /**
1389
     * Checks if multiple joined multiple-valued collections is hydrated correctly.
1390
     *
1391
     * SELECT PARTIAL u.{id, status}, PARTIAL g.{id, name}, PARTIAL p.{phonenumber}
1392
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1393
     *
1394
     * @group DDC-809
1395
     */
1396
    public function testManyToManyHydration()
1397
    {
1398
        $rsm = new ResultSetMapping;
1399
        $rsm->addEntityResult(CmsUser::class, 'u');
1400
        $rsm->addFieldResult('u', 'u__id', 'id');
1401
        $rsm->addFieldResult('u', 'u__name', 'name');
1402
        $rsm->addJoinedEntityResult(CmsGroup::class, 'g', 'u', 'groups');
1403
        $rsm->addFieldResult('g', 'g__id', 'id');
1404
        $rsm->addFieldResult('g', 'g__name', 'name');
1405
        $rsm->addJoinedEntityResult(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
1406
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1407
1408
        // Faked result set
1409
        $resultSet = [
1410
            [
1411
                'u__id' => '1',
1412
                'u__name' => 'romanb',
1413
                'g__id' => '3',
1414
                'g__name' => 'TestGroupB',
1415
                'p__phonenumber' => 1111,
1416
            ],
1417
            [
1418
                'u__id' => '1',
1419
                'u__name' => 'romanb',
1420
                'g__id' => '5',
1421
                'g__name' => 'TestGroupD',
1422
                'p__phonenumber' => 1111,
1423
            ],
1424
            [
1425
                'u__id' => '1',
1426
                'u__name' => 'romanb',
1427
                'g__id' => '3',
1428
                'g__name' => 'TestGroupB',
1429
                'p__phonenumber' => 2222,
1430
            ],
1431
            [
1432
                'u__id' => '1',
1433
                'u__name' => 'romanb',
1434
                'g__id' => '5',
1435
                'g__name' => 'TestGroupD',
1436
                'p__phonenumber' => 2222,
1437
            ],
1438
            [
1439
                'u__id' => '2',
1440
                'u__name' => 'jwage',
1441
                'g__id' => '2',
1442
                'g__name' => 'TestGroupA',
1443
                'p__phonenumber' => 3333,
1444
            ],
1445
            [
1446
                'u__id' => '2',
1447
                'u__name' => 'jwage',
1448
                'g__id' => '3',
1449
                'g__name' => 'TestGroupB',
1450
                'p__phonenumber' => 3333,
1451
            ],
1452
            [
1453
                'u__id' => '2',
1454
                'u__name' => 'jwage',
1455
                'g__id' => '4',
1456
                'g__name' => 'TestGroupC',
1457
                'p__phonenumber' => 3333,
1458
            ],
1459
            [
1460
                'u__id' => '2',
1461
                'u__name' => 'jwage',
1462
                'g__id' => '5',
1463
                'g__name' => 'TestGroupD',
1464
                'p__phonenumber' => 3333,
1465
            ],
1466
            [
1467
                'u__id' => '2',
1468
                'u__name' => 'jwage',
1469
                'g__id' => '2',
1470
                'g__name' => 'TestGroupA',
1471
                'p__phonenumber' => 4444,
1472
            ],
1473
            [
1474
                'u__id' => '2',
1475
                'u__name' => 'jwage',
1476
                'g__id' => '3',
1477
                'g__name' => 'TestGroupB',
1478
                'p__phonenumber' => 4444,
1479
            ],
1480
            [
1481
                'u__id' => '2',
1482
                'u__name' => 'jwage',
1483
                'g__id' => '4',
1484
                'g__name' => 'TestGroupC',
1485
                'p__phonenumber' => 4444,
1486
            ],
1487
            [
1488
                'u__id' => '2',
1489
                'u__name' => 'jwage',
1490
                'g__id' => '5',
1491
                'g__name' => 'TestGroupD',
1492
                'p__phonenumber' => 4444,
1493
            ],
1494
        ];
1495
1496
        $stmt     = new HydratorMockStatement($resultSet);
1497
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1498
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1499
1500
        self::assertEquals(2, count($result));
1501
1502
        self::assertContainsOnly(CmsUser::class, $result);
1503
1504
        self::assertEquals(2, count($result[0]->groups));
1505
        self::assertEquals(2, count($result[0]->phonenumbers));
1506
1507
        self::assertEquals(4, count($result[1]->groups));
1508
        self::assertEquals(2, count($result[1]->phonenumbers));
1509
    }
1510
1511
    /**
1512
     * Checks if multiple joined multiple-valued collections is hydrated correctly.
1513
     *
1514
     * SELECT PARTIAL u.{id, status} As user, PARTIAL g.{id, name}, PARTIAL p.{phonenumber}
1515
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1516
     *
1517
     * @group DDC-809
1518
     */
1519
    public function testManyToManyHydrationWithAliasedUserEntity()
1520
    {
1521
        $rsm = new ResultSetMapping;
1522
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1523
        $rsm->addFieldResult('u', 'u__id', 'id');
1524
        $rsm->addFieldResult('u', 'u__name', 'name');
1525
        $rsm->addJoinedEntityResult(CmsGroup::class, 'g', 'u', 'groups');
1526
        $rsm->addFieldResult('g', 'g__id', 'id');
1527
        $rsm->addFieldResult('g', 'g__name', 'name');
1528
        $rsm->addJoinedEntityResult(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
1529
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1530
1531
        // Faked result set
1532
        $resultSet = [
1533
            [
1534
                'u__id' => '1',
1535
                'u__name' => 'romanb',
1536
                'g__id' => '3',
1537
                'g__name' => 'TestGroupB',
1538
                'p__phonenumber' => 1111,
1539
            ],
1540
            [
1541
                'u__id' => '1',
1542
                'u__name' => 'romanb',
1543
                'g__id' => '5',
1544
                'g__name' => 'TestGroupD',
1545
                'p__phonenumber' => 1111,
1546
            ],
1547
            [
1548
                'u__id' => '1',
1549
                'u__name' => 'romanb',
1550
                'g__id' => '3',
1551
                'g__name' => 'TestGroupB',
1552
                'p__phonenumber' => 2222,
1553
            ],
1554
            [
1555
                'u__id' => '1',
1556
                'u__name' => 'romanb',
1557
                'g__id' => '5',
1558
                'g__name' => 'TestGroupD',
1559
                'p__phonenumber' => 2222,
1560
            ],
1561
            [
1562
                'u__id' => '2',
1563
                'u__name' => 'jwage',
1564
                'g__id' => '2',
1565
                'g__name' => 'TestGroupA',
1566
                'p__phonenumber' => 3333,
1567
            ],
1568
            [
1569
                'u__id' => '2',
1570
                'u__name' => 'jwage',
1571
                'g__id' => '3',
1572
                'g__name' => 'TestGroupB',
1573
                'p__phonenumber' => 3333,
1574
            ],
1575
            [
1576
                'u__id' => '2',
1577
                'u__name' => 'jwage',
1578
                'g__id' => '4',
1579
                'g__name' => 'TestGroupC',
1580
                'p__phonenumber' => 3333,
1581
            ],
1582
            [
1583
                'u__id' => '2',
1584
                'u__name' => 'jwage',
1585
                'g__id' => '5',
1586
                'g__name' => 'TestGroupD',
1587
                'p__phonenumber' => 3333,
1588
            ],
1589
            [
1590
                'u__id' => '2',
1591
                'u__name' => 'jwage',
1592
                'g__id' => '2',
1593
                'g__name' => 'TestGroupA',
1594
                'p__phonenumber' => 4444,
1595
            ],
1596
            [
1597
                'u__id' => '2',
1598
                'u__name' => 'jwage',
1599
                'g__id' => '3',
1600
                'g__name' => 'TestGroupB',
1601
                'p__phonenumber' => 4444,
1602
            ],
1603
            [
1604
                'u__id' => '2',
1605
                'u__name' => 'jwage',
1606
                'g__id' => '4',
1607
                'g__name' => 'TestGroupC',
1608
                'p__phonenumber' => 4444,
1609
            ],
1610
            [
1611
                'u__id' => '2',
1612
                'u__name' => 'jwage',
1613
                'g__id' => '5',
1614
                'g__name' => 'TestGroupD',
1615
                'p__phonenumber' => 4444,
1616
            ],
1617
        ];
1618
1619
        $stmt     = new HydratorMockStatement($resultSet);
1620
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1621
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1622
1623
        self::assertEquals(2, count($result));
1624
1625
        self::assertInternalType('array', $result[0]);
1626
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1627
        self::assertInternalType('array', $result[1]);
1628
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
1629
1630
        self::assertEquals(2, count($result[0]['user']->groups));
1631
        self::assertEquals(2, count($result[0]['user']->phonenumbers));
1632
1633
        self::assertEquals(4, count($result[1]['user']->groups));
1634
        self::assertEquals(2, count($result[1]['user']->phonenumbers));
1635
    }
1636
1637
    /**
1638
     * SELECT PARTIAL u.{id, status}, UPPER(u.name) as nameUpper
1639
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1640
     *
1641
     * @group DDC-1358
1642
     * @dataProvider provideDataForUserEntityResult
1643
     */
1644
    public function testMissingIdForRootEntity($userEntityKey)
1645
    {
1646
        $rsm = new ResultSetMapping;
1647
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1648
        $rsm->addFieldResult('u', 'u__id', 'id');
1649
        $rsm->addFieldResult('u', 'u__status', 'status');
1650
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1651
1652
        // Faked result set
1653
        $resultSet = [
1654
            //row1
1655
            [
1656
                'u__id' => '1',
1657
                'u__status' => 'developer',
1658
                'sclr0' => 'ROMANB',
1659
            ],
1660
            [
1661
                'u__id' => null,
1662
                'u__status' => null,
1663
                'sclr0' => 'ROMANB',
1664
            ],
1665
            [
1666
                'u__id' => '2',
1667
                'u__status' => 'developer',
1668
                'sclr0' => 'JWAGE',
1669
            ],
1670
            [
1671
                'u__id' => null,
1672
                'u__status' => null,
1673
                'sclr0' => 'JWAGE',
1674
            ],
1675
        ];
1676
1677
        $stmt     = new HydratorMockStatement($resultSet);
1678
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1679
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1680
1681
        self::assertEquals(4, count($result), "Should hydrate four results.");
1682
1683
        self::assertEquals('ROMANB', $result[0]['nameUpper']);
1684
        self::assertEquals('ROMANB', $result[1]['nameUpper']);
1685
        self::assertEquals('JWAGE', $result[2]['nameUpper']);
1686
        self::assertEquals('JWAGE', $result[3]['nameUpper']);
1687
1688
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
1689
        self::assertNull($result[1][$userEntityKey]);
1690
1691
        self::assertInstanceOf(CmsUser::class, $result[2][$userEntityKey]);
1692
        self::assertNull($result[3][$userEntityKey]);
1693
    }
1694
1695
    /**
1696
     * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) AS nameUpper
1697
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1698
     *   LEFT JOIN u.phonenumbers u
1699
     *
1700
     * @group DDC-1358
1701
     * @dataProvider provideDataForUserEntityResult
1702
     */
1703
    public function testMissingIdForCollectionValuedChildEntity($userEntityKey)
1704
    {
1705
        $rsm = new ResultSetMapping;
1706
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1707
        $rsm->addJoinedEntityResult(
1708
            CmsPhonenumber::class,
1709
            'p',
1710
            'u',
1711
            'phonenumbers'
1712
        );
1713
        $rsm->addFieldResult('u', 'u__id', 'id');
1714
        $rsm->addFieldResult('u', 'u__status', 'status');
1715
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1716
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1717
1718
        // Faked result set
1719
        $resultSet = [
1720
            //row1
1721
            [
1722
                'u__id' => '1',
1723
                'u__status' => 'developer',
1724
                'sclr0' => 'ROMANB',
1725
                'p__phonenumber' => '42',
1726
            ],
1727
            [
1728
                'u__id' => '1',
1729
                'u__status' => 'developer',
1730
                'sclr0' => 'ROMANB',
1731
                'p__phonenumber' => null
1732
            ],
1733
            [
1734
                'u__id' => '2',
1735
                'u__status' => 'developer',
1736
                'sclr0' => 'JWAGE',
1737
                'p__phonenumber' => '91'
1738
            ],
1739
            [
1740
                'u__id' => '2',
1741
                'u__status' => 'developer',
1742
                'sclr0' => 'JWAGE',
1743
                'p__phonenumber' => null
1744
            ]
1745
        ];
1746
1747
        $stmt     = new HydratorMockStatement($resultSet);
1748
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1749
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1750
1751
        self::assertEquals(2, count($result));
1752
1753
        self::assertEquals(1, $result[0][$userEntityKey]->phonenumbers->count());
1754
        self::assertEquals(1, $result[1][$userEntityKey]->phonenumbers->count());
1755
    }
1756
1757
    /**
1758
     * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, city}, UPPER(u.name) AS nameUpper
1759
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1760
     *   JOIN u.address a
1761
     *
1762
     * @group DDC-1358
1763
     * @dataProvider provideDataForUserEntityResult
1764
     */
1765
    public function testMissingIdForSingleValuedChildEntity($userEntityKey)
1766
    {
1767
        $rsm = new ResultSetMapping;
1768
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1769
        $rsm->addJoinedEntityResult(
1770
            CmsAddress::class,
1771
            'a',
1772
            'u',
1773
            'address'
1774
        );
1775
        $rsm->addFieldResult('u', 'u__id', 'id');
1776
        $rsm->addFieldResult('u', 'u__status', 'status');
1777
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1778
        $rsm->addFieldResult('a', 'a__id', 'id');
1779
        $rsm->addFieldResult('a', 'a__city', 'city');
1780
        $rsm->addMetaResult('a', 'user_id', 'user_id', false, Type::getType('string'));
1781
1782
        // Faked result set
1783
        $resultSet = [
1784
            //row1
1785
            [
1786
                'u__id' => '1',
1787
                'u__status' => 'developer',
1788
                'sclr0' => 'ROMANB',
1789
                'a__id' => 1,
1790
                'a__city' => 'Berlin',
1791
            ],
1792
            [
1793
                'u__id' => '2',
1794
                'u__status' => 'developer',
1795
                'sclr0' => 'BENJAMIN',
1796
                'a__id' => null,
1797
                'a__city' => null,
1798
            ],
1799
        ];
1800
1801
        $stmt     = new HydratorMockStatement($resultSet);
1802
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1803
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1804
1805
        self::assertEquals(2, count($result));
1806
1807
        self::assertInstanceOf(CmsAddress::class, $result[0][$userEntityKey]->address);
1808
        self::assertNull($result[1][$userEntityKey]->address);
1809
    }
1810
1811
    /**
1812
     * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
1813
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1814
     *        INDEX BY u.id
1815
     *
1816
     * @group DDC-1385
1817
     * @dataProvider provideDataForUserEntityResult
1818
     */
1819
    public function testIndexByAndMixedResult($userEntityKey)
1820
    {
1821
        $rsm = new ResultSetMapping;
1822
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1823
        $rsm->addFieldResult('u', 'u__id', 'id');
1824
        $rsm->addFieldResult('u', 'u__status', 'status');
1825
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1826
        $rsm->addIndexBy('u', 'id');
1827
1828
        // Faked result set
1829
        $resultSet = [
1830
            //row1
1831
            [
1832
                'u__id' => '1',
1833
                'u__status' => 'developer',
1834
                'sclr0' => 'ROMANB',
1835
            ],
1836
            [
1837
                'u__id' => '2',
1838
                'u__status' => 'developer',
1839
                'sclr0' => 'JWAGE',
1840
            ],
1841
        ];
1842
1843
        $stmt     = new HydratorMockStatement($resultSet);
1844
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1845
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1846
1847
        self::assertEquals(2, count($result));
1848
1849
        self::assertTrue(isset($result[1]));
1850
        self::assertEquals(1, $result[1][$userEntityKey]->id);
1851
1852
        self::assertTrue(isset($result[2]));
1853
        self::assertEquals(2, $result[2][$userEntityKey]->id);
1854
    }
1855
1856
    /**
1857
     * SELECT UPPER(u.name) AS nameUpper
1858
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1859
     *
1860
     * @group DDC-1385
1861
     * @dataProvider provideDataForUserEntityResult
1862
     */
1863
    public function testIndexByScalarsOnly($userEntityKey)
1864
    {
1865
        $rsm = new ResultSetMapping;
1866
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1867
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1868
        $rsm->addIndexByScalar('sclr0');
1869
1870
        // Faked result set
1871
        $resultSet = [
1872
            //row1
1873
            [
1874
                'sclr0' => 'ROMANB',
1875
            ],
1876
            [
1877
                'sclr0' => 'JWAGE',
1878
            ],
1879
        ];
1880
1881
        $stmt     = new HydratorMockStatement($resultSet);
1882
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1883
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1884
1885
        self::assertEquals(
1886
            [
1887
                'ROMANB' => ['nameUpper' => 'ROMANB'],
1888
                'JWAGE'  => ['nameUpper' => 'JWAGE']
1889
            ],
1890
            $result
1891
        );
1892
    }
1893
1894
1895
    /**
1896
     * @group DDC-1470
1897
     *
1898
     * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
1899
     * @expectedExceptionMessage The meta mapping for the discriminator column "c_discr" is missing for "Doctrine\Tests\Models\Company\CompanyFixContract" using the DQL alias "c".
1900
     */
1901
    public function testMissingMetaMappingException()
1902
    {
1903
        $rsm = new ResultSetMapping;
1904
1905
        $rsm->addEntityResult(CompanyFixContract::class, 'c');
1906
        $rsm->addJoinedEntityResult(CompanyEmployee::class, 'e', 'c', 'salesPerson');
1907
        $rsm->addFieldResult('c', 'c__id', 'id');
1908
        $rsm->setDiscriminatorColumn('c', 'c_discr');
1909
1910
        $resultSet = [
1911
              [
1912
                  'c__id'   => '1',
1913
                  'c_discr' => 'fix',
1914
              ],
1915
        ];
1916
1917
        $stmt     = new HydratorMockStatement($resultSet);
1918
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1919
        $hydrator->hydrateAll($stmt, $rsm);
1920
    }
1921
1922
    /**
1923
     * @group DDC-1470
1924
     *
1925
     * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
1926
     * @expectedExceptionMessage The discriminator column "discr" is missing for "Doctrine\Tests\Models\Company\CompanyEmployee" using the DQL alias "e".
1927
     */
1928
    public function testMissingDiscriminatorColumnException()
1929
    {
1930
        $rsm = new ResultSetMapping;
1931
1932
        $rsm->addEntityResult(CompanyFixContract::class, 'c');
1933
        $rsm->addJoinedEntityResult(CompanyEmployee::class, 'e', 'c', 'salesPerson');
1934
        $rsm->addFieldResult('c', 'c__id', 'id');
1935
        $rsm->addMetaResult('c', 'c_discr', 'discr', false, Type::getType('string'));
1936
        $rsm->setDiscriminatorColumn('c', 'c_discr');
1937
        $rsm->addFieldResult('e', 'e__id', 'id');
1938
        $rsm->addFieldResult('e', 'e__name', 'name');
1939
        $rsm->addMetaResult('e ', 'e_discr', 'discr', false, Type::getType('string'));
1940
        $rsm->setDiscriminatorColumn('e', 'e_discr');
1941
1942
        $resultSet = [
1943
              [
1944
                  'c__id'   => '1',
1945
                  'c_discr' => 'fix',
1946
                  'e__id'   => '1',
1947
                  'e__name' => 'Fabio B. Silva'
1948
              ],
1949
        ];
1950
1951
        $stmt     = new HydratorMockStatement($resultSet);
1952
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1953
        $hydrator->hydrateAll($stmt, $rsm);
1954
    }
1955
1956
    /**
1957
     * @group DDC-3076
1958
     *
1959
     * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
1960
     * @expectedExceptionMessage The discriminator value "subworker" is invalid. It must be one of "person", "manager", "employee".
1961
     */
1962 View Code Duplication
    public function testInvalidDiscriminatorValueException()
1963
    {
1964
        $rsm = new ResultSetMapping;
1965
1966
        $rsm->addEntityResult(CompanyPerson::class, 'p');
1967
        $rsm->addFieldResult('p', 'p__id', 'id');
1968
        $rsm->addFieldResult('p', 'p__name', 'name');
1969
        $rsm->addMetaResult('p', 'discr', 'discr', false, Type::getType('string'));
1970
        $rsm->setDiscriminatorColumn('p', 'discr');
1971
1972
        $resultSet = [
1973
              [
1974
                  'p__id'   => '1',
1975
                  'p__name' => 'Fabio B. Silva',
1976
                  'discr'   => 'subworker'
1977
              ],
1978
        ];
1979
1980
        $stmt       = new HydratorMockStatement($resultSet);
1981
        $hydrator   = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1982
        $hydrator->hydrateAll($stmt, $rsm);
1983
    }
1984
1985
    public function testFetchJoinCollectionValuedAssociationWithDefaultArrayValue()
1986
    {
1987
        $rsm = new ResultSetMapping;
1988
1989
        $rsm->addEntityResult(EntityWithArrayDefaultArrayValueM2M::class, 'e1', null);
1990
        $rsm->addJoinedEntityResult(SimpleEntity::class, 'e2', 'e1', 'collection');
1991
        $rsm->addFieldResult('e1', 'a1__id', 'id');
1992
        $rsm->addFieldResult('e2', 'e2__id', 'id');
1993
1994
        $resultSet = [
1995
            [
1996
                'a1__id' => '1',
1997
                'e2__id' => '1',
1998
            ]
1999
        ];
2000
2001
        $stmt     = new HydratorMockStatement($resultSet);
2002
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
2003
        $result   = $hydrator->hydrateAll($stmt, $rsm);
2004
2005
        self::assertCount(1, $result);
2006
        self::assertInstanceOf(EntityWithArrayDefaultArrayValueM2M::class, $result[0]);
2007
        self::assertInstanceOf(PersistentCollection::class, $result[0]->collection);
2008
        self::assertCount(1, $result[0]->collection);
2009
        self::assertInstanceOf(SimpleEntity::class, $result[0]->collection[0]);
2010
    }
2011
2012
    /**
2013
     * @param object $object
2014
     * @param string $propertyName
2015
     * @param mixed  $newValue
2016
     */
2017
    private function swapPrivateProperty($object, string $propertyName, $newValue)
2018
    {
2019
        $reflectionClass    = new \ReflectionClass($object);
2020
        $reflectionProperty = $reflectionClass->getProperty($propertyName);
2021
2022
        $reflectionProperty->setAccessible(true);
2023
2024
        $reflectionProperty->setValue($object, $newValue);
2025
    }
2026
}
2027