Completed
Push — master ( 23a060...e747f7 )
by Luís
45s queued 37s
created

ObjectHydratorTest::swapPrivateProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 8
rs 10
c 0
b 0
f 0
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\Internal\Hydration\ObjectHydrator;
9
use Doctrine\ORM\Mapping\FetchMode;
10
use Doctrine\ORM\PersistentCollection;
11
use Doctrine\ORM\Proxy\Factory\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
use ProxyManager\Configuration;
31
use ProxyManager\Factory\LazyLoadingGhostFactory;
32
33
class ObjectHydratorTest extends HydrationTestCase
34
{
35
    public function provideDataForUserEntityResult()
36
    {
37
        return [
38
            [0],
39
            ['user'],
40
        ];
41
    }
42
43
    public function provideDataForMultipleRootEntityResult()
44
    {
45
        return [
46
            [0, 0],
47
            ['user', 0],
48
            [0, 'article'],
49
            ['user', 'article'],
50
        ];
51
    }
52
53
    public function provideDataForProductEntityResult()
54
    {
55
        return [
56
            [0],
57
            ['product'],
58
        ];
59
    }
60
61
    /**
62
     * SELECT PARTIAL u.{id,name}
63
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
64
     */
65
    public function testSimpleEntityQuery() : void
66
    {
67
        $rsm = new ResultSetMapping();
68
        $rsm->addEntityResult(CmsUser::class, 'u');
69
        $rsm->addFieldResult('u', 'u__id', 'id');
70
        $rsm->addFieldResult('u', 'u__name', 'name');
71
72
        // Faked result set
73
        $resultSet = [
74
            [
75
                'u__id' => '1',
76
                'u__name' => 'romanb',
77
            ],
78
            [
79
                'u__id' => '2',
80
                'u__name' => 'jwage',
81
            ],
82
        ];
83
84
        $stmt     = new HydratorMockStatement($resultSet);
85
        $hydrator = new ObjectHydrator($this->em);
86
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
87
88
        self::assertCount(2, $result);
89
90
        self::assertInstanceOf(CmsUser::class, $result[0]);
91
        self::assertInstanceOf(CmsUser::class, $result[1]);
92
93
        self::assertEquals(1, $result[0]->id);
94
        self::assertEquals('romanb', $result[0]->name);
95
96
        self::assertEquals(2, $result[1]->id);
97
        self::assertEquals('jwage', $result[1]->name);
98
    }
99
100
    /**
101
     * SELECT PARTIAL u.{id,name} AS user
102
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
103
     */
104
    public function testSimpleEntityQueryWithAliasedUserEntity() : void
105
    {
106
        $rsm = new ResultSetMapping();
107
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
108
        $rsm->addFieldResult('u', 'u__id', 'id');
109
        $rsm->addFieldResult('u', 'u__name', 'name');
110
111
        // Faked result set
112
        $resultSet = [
113
            [
114
                'u__id' => '1',
115
                'u__name' => 'romanb',
116
            ],
117
            [
118
                'u__id' => '2',
119
                'u__name' => 'jwage',
120
            ],
121
        ];
122
123
        $stmt     = new HydratorMockStatement($resultSet);
124
        $hydrator = new ObjectHydrator($this->em);
125
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
126
127
        self::assertCount(2, $result);
128
129
        self::assertArrayHasKey('user', $result[0]);
130
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
131
132
        self::assertArrayHasKey('user', $result[1]);
133
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
134
135
        self::assertEquals(1, $result[0]['user']->id);
136
        self::assertEquals('romanb', $result[0]['user']->name);
137
138
        self::assertEquals(2, $result[1]['user']->id);
139
        self::assertEquals('jwage', $result[1]['user']->name);
140
    }
141
142
    /**
143
     * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic}
144
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
145
     */
146
    public function testSimpleMultipleRootEntityQuery() : void
147
    {
148
        $rsm = new ResultSetMapping();
149
        $rsm->addEntityResult(CmsUser::class, 'u');
150
        $rsm->addEntityResult(CmsArticle::class, 'a');
151
        $rsm->addFieldResult('u', 'u__id', 'id');
152
        $rsm->addFieldResult('u', 'u__name', 'name');
153
        $rsm->addFieldResult('a', 'a__id', 'id');
154
        $rsm->addFieldResult('a', 'a__topic', 'topic');
155
156
        // Faked result set
157
        $resultSet = [
158
            [
159
                'u__id' => '1',
160
                'u__name' => 'romanb',
161
                'a__id' => '1',
162
                'a__topic' => 'Cool things.',
163
            ],
164
            [
165
                'u__id' => '2',
166
                'u__name' => 'jwage',
167
                'a__id' => '2',
168
                'a__topic' => 'Cool things II.',
169
            ],
170
        ];
171
172
        $stmt     = new HydratorMockStatement($resultSet);
173
        $hydrator = new ObjectHydrator($this->em);
174
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
175
176
        self::assertCount(4, $result);
177
178
        self::assertInstanceOf(CmsUser::class, $result[0]);
179
        self::assertInstanceOf(CmsArticle::class, $result[1]);
180
        self::assertInstanceOf(CmsUser::class, $result[2]);
181
        self::assertInstanceOf(CmsArticle::class, $result[3]);
182
183
        self::assertEquals(1, $result[0]->id);
184
        self::assertEquals('romanb', $result[0]->name);
185
186
        self::assertEquals(1, $result[1]->id);
187
        self::assertEquals('Cool things.', $result[1]->topic);
188
189
        self::assertEquals(2, $result[2]->id);
190
        self::assertEquals('jwage', $result[2]->name);
191
192
        self::assertEquals(2, $result[3]->id);
193
        self::assertEquals('Cool things II.', $result[3]->topic);
194
    }
195
196
    /**
197
     * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic}
198
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
199
     */
200
    public function testSimpleMultipleRootEntityQueryWithAliasedUserEntity() : void
201
    {
202
        $rsm = new ResultSetMapping();
203
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
204
        $rsm->addEntityResult(CmsArticle::class, 'a');
205
        $rsm->addFieldResult('u', 'u__id', 'id');
206
        $rsm->addFieldResult('u', 'u__name', 'name');
207
        $rsm->addFieldResult('a', 'a__id', 'id');
208
        $rsm->addFieldResult('a', 'a__topic', 'topic');
209
210
        // Faked result set
211
        $resultSet = [
212
            [
213
                'u__id' => '1',
214
                'u__name' => 'romanb',
215
                'a__id' => '1',
216
                'a__topic' => 'Cool things.',
217
            ],
218
            [
219
                'u__id' => '2',
220
                'u__name' => 'jwage',
221
                'a__id' => '2',
222
                'a__topic' => 'Cool things II.',
223
            ],
224
        ];
225
226
        $stmt     = new HydratorMockStatement($resultSet);
227
        $hydrator = new ObjectHydrator($this->em);
228
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
229
230
        self::assertCount(4, $result);
231
232
        self::assertArrayHasKey('user', $result[0]);
233
        self::assertArrayNotHasKey(0, $result[0]);
234
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
235
        self::assertEquals(1, $result[0]['user']->id);
236
        self::assertEquals('romanb', $result[0]['user']->name);
237
238
        self::assertArrayHasKey(0, $result[1]);
239
        self::assertArrayNotHasKey('user', $result[1]);
240
        self::assertInstanceOf(CmsArticle::class, $result[1][0]);
241
        self::assertEquals(1, $result[1][0]->id);
242
        self::assertEquals('Cool things.', $result[1][0]->topic);
243
244
        self::assertArrayHasKey('user', $result[2]);
245
        self::assertArrayNotHasKey(0, $result[2]);
246
        self::assertInstanceOf(CmsUser::class, $result[2]['user']);
247
        self::assertEquals(2, $result[2]['user']->id);
248
        self::assertEquals('jwage', $result[2]['user']->name);
249
250
        self::assertArrayHasKey(0, $result[3]);
251
        self::assertArrayNotHasKey('user', $result[3]);
252
        self::assertInstanceOf(CmsArticle::class, $result[3][0]);
253
        self::assertEquals(2, $result[3][0]->id);
254
        self::assertEquals('Cool things II.', $result[3][0]->topic);
255
    }
256
257
    /**
258
     * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} AS article
259
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
260
     */
261
    public function testSimpleMultipleRootEntityQueryWithAliasedArticleEntity() : void
262
    {
263
        $rsm = new ResultSetMapping();
264
        $rsm->addEntityResult(CmsUser::class, 'u');
265
        $rsm->addEntityResult(CmsArticle::class, 'a', 'article');
266
        $rsm->addFieldResult('u', 'u__id', 'id');
267
        $rsm->addFieldResult('u', 'u__name', 'name');
268
        $rsm->addFieldResult('a', 'a__id', 'id');
269
        $rsm->addFieldResult('a', 'a__topic', 'topic');
270
271
        // Faked result set
272
        $resultSet = [
273
            [
274
                'u__id' => '1',
275
                'u__name' => 'romanb',
276
                'a__id' => '1',
277
                'a__topic' => 'Cool things.',
278
            ],
279
            [
280
                'u__id' => '2',
281
                'u__name' => 'jwage',
282
                'a__id' => '2',
283
                'a__topic' => 'Cool things II.',
284
            ],
285
        ];
286
287
        $stmt     = new HydratorMockStatement($resultSet);
288
        $hydrator = new ObjectHydrator($this->em);
289
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
290
291
        self::assertCount(4, $result);
292
293
        self::assertArrayHasKey(0, $result[0]);
294
        self::assertArrayNotHasKey('article', $result[0]);
295
        self::assertInstanceOf(CmsUser::class, $result[0][0]);
296
        self::assertEquals(1, $result[0][0]->id);
297
        self::assertEquals('romanb', $result[0][0]->name);
298
299
        self::assertArrayHasKey('article', $result[1]);
300
        self::assertArrayNotHasKey(0, $result[1]);
301
        self::assertInstanceOf(CmsArticle::class, $result[1]['article']);
302
        self::assertEquals(1, $result[1]['article']->id);
303
        self::assertEquals('Cool things.', $result[1]['article']->topic);
304
305
        self::assertArrayHasKey(0, $result[2]);
306
        self::assertArrayNotHasKey('article', $result[2]);
307
        self::assertInstanceOf(CmsUser::class, $result[2][0]);
308
        self::assertEquals(2, $result[2][0]->id);
309
        self::assertEquals('jwage', $result[2][0]->name);
310
311
        self::assertArrayHasKey('article', $result[3]);
312
        self::assertArrayNotHasKey(0, $result[3]);
313
        self::assertInstanceOf(CmsArticle::class, $result[3]['article']);
314
        self::assertEquals(2, $result[3]['article']->id);
315
        self::assertEquals('Cool things II.', $result[3]['article']->topic);
316
    }
317
318
    /**
319
     * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} AS article
320
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
321
     */
322
    public function testSimpleMultipleRootEntityQueryWithAliasedEntities() : void
323
    {
324
        $rsm = new ResultSetMapping();
325
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
326
        $rsm->addEntityResult(CmsArticle::class, 'a', 'article');
327
        $rsm->addFieldResult('u', 'u__id', 'id');
328
        $rsm->addFieldResult('u', 'u__name', 'name');
329
        $rsm->addFieldResult('a', 'a__id', 'id');
330
        $rsm->addFieldResult('a', 'a__topic', 'topic');
331
332
        // Faked result set
333
        $resultSet = [
334
            [
335
                'u__id' => '1',
336
                'u__name' => 'romanb',
337
                'a__id' => '1',
338
                'a__topic' => 'Cool things.',
339
            ],
340
            [
341
                'u__id' => '2',
342
                'u__name' => 'jwage',
343
                'a__id' => '2',
344
                'a__topic' => 'Cool things II.',
345
            ],
346
        ];
347
348
        $stmt     = new HydratorMockStatement($resultSet);
349
        $hydrator = new ObjectHydrator($this->em);
350
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
351
352
        self::assertCount(4, $result);
353
354
        self::assertArrayHasKey('user', $result[0]);
355
        self::assertArrayNotHasKey('article', $result[0]);
356
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
357
        self::assertEquals(1, $result[0]['user']->id);
358
        self::assertEquals('romanb', $result[0]['user']->name);
359
360
        self::assertArrayHasKey('article', $result[1]);
361
        self::assertArrayNotHasKey('user', $result[1]);
362
        self::assertInstanceOf(CmsArticle::class, $result[1]['article']);
363
        self::assertEquals(1, $result[1]['article']->id);
364
        self::assertEquals('Cool things.', $result[1]['article']->topic);
365
366
        self::assertArrayHasKey('user', $result[2]);
367
        self::assertArrayNotHasKey('article', $result[2]);
368
        self::assertInstanceOf(CmsUser::class, $result[2]['user']);
369
        self::assertEquals(2, $result[2]['user']->id);
370
        self::assertEquals('jwage', $result[2]['user']->name);
371
372
        self::assertArrayHasKey('article', $result[3]);
373
        self::assertArrayNotHasKey('user', $result[3]);
374
        self::assertInstanceOf(CmsArticle::class, $result[3]['article']);
375
        self::assertEquals(2, $result[3]['article']->id);
376
        self::assertEquals('Cool things II.', $result[3]['article']->topic);
377
    }
378
379
    /**
380
     * SELECT PARTIAL u.{id, status}, COUNT(p.phonenumber) numPhones
381
     *   FROM User u
382
     *   JOIN u.phonenumbers p
383
     *  GROUP BY u.id
384
     *
385
     * @dataProvider provideDataForUserEntityResult
386
     */
387
    public function testMixedQueryNormalJoin($userEntityKey) : void
388
    {
389
        $rsm = new ResultSetMapping();
390
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
391
        $rsm->addFieldResult('u', 'u__id', 'id');
392
        $rsm->addFieldResult('u', 'u__status', 'status');
393
        $rsm->addScalarResult('sclr0', 'numPhones', Type::getType('integer'));
394
395
        // Faked result set
396
        $resultSet = [
397
            //row1
398
            [
399
                'u__id' => '1',
400
                'u__status' => 'developer',
401
                'sclr0' => '2',
402
            ],
403
            [
404
                'u__id' => '2',
405
                'u__status' => 'developer',
406
                'sclr0' => '1',
407
            ],
408
        ];
409
410
        $stmt     = new HydratorMockStatement($resultSet);
411
        $hydrator = new ObjectHydrator($this->em);
412
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
413
414
        self::assertCount(2, $result);
415
416
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

416
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
417
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

417
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
418
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

418
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
419
420
        // first user => 2 phonenumbers
421
        self::assertEquals(2, $result[0]['numPhones']);
422
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
423
424
        // second user => 1 phonenumber
425
        self::assertEquals(1, $result[1]['numPhones']);
426
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
427
    }
428
429
    /**
430
     * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) nameUpper
431
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
432
     *   JOIN u.phonenumbers p
433
     *
434
     * @dataProvider provideDataForUserEntityResult
435
     */
436
    public function testMixedQueryFetchJoin($userEntityKey) : void
437
    {
438
        $rsm = new ResultSetMapping();
439
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
440
        $rsm->addJoinedEntityResult(
441
            CmsPhonenumber::class,
442
            'p',
443
            'u',
444
            'phonenumbers'
445
        );
446
        $rsm->addFieldResult('u', 'u__id', 'id');
447
        $rsm->addFieldResult('u', 'u__status', 'status');
448
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
449
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
450
451
        // Faked result set
452
        $resultSet = [
453
            //row1
454
            [
455
                'u__id' => '1',
456
                'u__status' => 'developer',
457
                'p__phonenumber' => '42',
458
                'sclr0' => 'ROMANB',
459
            ],
460
            [
461
                'u__id' => '1',
462
                'u__status' => 'developer',
463
                'p__phonenumber' => '43',
464
                'sclr0' => 'ROMANB',
465
            ],
466
            [
467
                'u__id' => '2',
468
                'u__status' => 'developer',
469
                'p__phonenumber' => '91',
470
                'sclr0' => 'JWAGE',
471
            ],
472
        ];
473
474
        $stmt     = new HydratorMockStatement($resultSet);
475
        $hydrator = new ObjectHydrator($this->em);
476
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
477
478
        self::assertCount(2, $result);
479
480
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

480
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
481
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

481
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
482
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

482
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
483
484
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
485
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
486
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
487
488
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
489
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
490
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
491
492
        // first user => 2 phonenumbers
493
        self::assertCount(2, $result[0][$userEntityKey]->phonenumbers);
494
        self::assertEquals('ROMANB', $result[0]['nameUpper']);
495
496
        // second user => 1 phonenumber
497
        self::assertCount(1, $result[1][$userEntityKey]->phonenumbers);
498
        self::assertEquals('JWAGE', $result[1]['nameUpper']);
499
500
        self::assertEquals(42, $result[0][$userEntityKey]->phonenumbers[0]->phonenumber);
501
        self::assertEquals(43, $result[0][$userEntityKey]->phonenumbers[1]->phonenumber);
502
        self::assertEquals(91, $result[1][$userEntityKey]->phonenumbers[0]->phonenumber);
503
    }
504
505
    /**
506
     * SELECT u, p, UPPER(u.name) nameUpper
507
     *   FROM User u
508
     *        INDEX BY u.id
509
     *   JOIN u.phonenumbers p
510
     *        INDEX BY p.phonenumber
511
     *
512
     * @dataProvider provideDataForUserEntityResult
513
     */
514
    public function testMixedQueryFetchJoinCustomIndex($userEntityKey) : void
515
    {
516
        $rsm = new ResultSetMapping();
517
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
518
        $rsm->addJoinedEntityResult(
519
            CmsPhonenumber::class,
520
            'p',
521
            'u',
522
            'phonenumbers'
523
        );
524
        $rsm->addFieldResult('u', 'u__id', 'id');
525
        $rsm->addFieldResult('u', 'u__status', 'status');
526
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
527
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
528
        $rsm->addIndexBy('u', 'id');
529
        $rsm->addIndexBy('p', 'phonenumber');
530
531
        // Faked result set
532
        $resultSet = [
533
            //row1
534
            [
535
                'u__id' => '1',
536
                'u__status' => 'developer',
537
                'sclr0' => 'ROMANB',
538
                'p__phonenumber' => '42',
539
            ],
540
            [
541
                'u__id' => '1',
542
                'u__status' => 'developer',
543
                'sclr0' => 'ROMANB',
544
                'p__phonenumber' => '43',
545
            ],
546
            [
547
                'u__id' => '2',
548
                'u__status' => 'developer',
549
                'sclr0' => 'JWAGE',
550
                'p__phonenumber' => '91',
551
            ],
552
        ];
553
554
        $stmt     = new HydratorMockStatement($resultSet);
555
        $hydrator = new ObjectHydrator($this->em);
556
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
557
558
        self::assertCount(2, $result);
559
560
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

560
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
561
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

561
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
562
        self::assertInternalType('array', $result[2]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

562
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[2]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
563
564
        // test the scalar values
565
        self::assertEquals('ROMANB', $result[1]['nameUpper']);
566
        self::assertEquals('JWAGE', $result[2]['nameUpper']);
567
568
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
569
        self::assertInstanceOf(CmsUser::class, $result[2][$userEntityKey]);
570
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
571
572
        // first user => 2 phonenumbers. notice the custom indexing by user id
573
        self::assertCount(2, $result[1][$userEntityKey]->phonenumbers);
574
575
        // second user => 1 phonenumber. notice the custom indexing by user id
576
        self::assertCount(1, $result[2][$userEntityKey]->phonenumbers);
577
578
        // test the custom indexing of the phonenumbers
579
        self::assertTrue(isset($result[1][$userEntityKey]->phonenumbers['42']));
580
        self::assertTrue(isset($result[1][$userEntityKey]->phonenumbers['43']));
581
        self::assertTrue(isset($result[2][$userEntityKey]->phonenumbers['91']));
582
    }
583
584
    /**
585
     * SELECT u, p, UPPER(u.name) nameUpper, a
586
     *   FROM User u
587
     *   JOIN u.phonenumbers p
588
     *   JOIN u.articles a
589
     *
590
     * @dataProvider provideDataForUserEntityResult
591
     */
592
    public function testMixedQueryMultipleFetchJoin($userEntityKey) : void
593
    {
594
        $rsm = new ResultSetMapping();
595
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
596
        $rsm->addJoinedEntityResult(
597
            CmsPhonenumber::class,
598
            'p',
599
            'u',
600
            'phonenumbers'
601
        );
602
        $rsm->addJoinedEntityResult(
603
            CmsArticle::class,
604
            'a',
605
            'u',
606
            'articles'
607
        );
608
        $rsm->addFieldResult('u', 'u__id', 'id');
609
        $rsm->addFieldResult('u', 'u__status', 'status');
610
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
611
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
612
        $rsm->addFieldResult('a', 'a__id', 'id');
613
        $rsm->addFieldResult('a', 'a__topic', 'topic');
614
615
        // Faked result set
616
        $resultSet = [
617
            //row1
618
            [
619
                'u__id' => '1',
620
                'u__status' => 'developer',
621
                'sclr0' => 'ROMANB',
622
                'p__phonenumber' => '42',
623
                'a__id' => '1',
624
                'a__topic' => 'Getting things done!',
625
            ],
626
            [
627
                'u__id' => '1',
628
                'u__status' => 'developer',
629
                'sclr0' => 'ROMANB',
630
                'p__phonenumber' => '43',
631
                'a__id' => '1',
632
                'a__topic' => 'Getting things done!',
633
            ],
634
            [
635
                'u__id' => '1',
636
                'u__status' => 'developer',
637
                'sclr0' => 'ROMANB',
638
                'p__phonenumber' => '42',
639
                'a__id' => '2',
640
                'a__topic' => 'ZendCon',
641
            ],
642
            [
643
                'u__id' => '1',
644
                'u__status' => 'developer',
645
                'sclr0' => 'ROMANB',
646
                'p__phonenumber' => '43',
647
                'a__id' => '2',
648
                'a__topic' => 'ZendCon',
649
            ],
650
            [
651
                'u__id' => '2',
652
                'u__status' => 'developer',
653
                'sclr0' => 'JWAGE',
654
                'p__phonenumber' => '91',
655
                'a__id' => '3',
656
                'a__topic' => 'LINQ',
657
            ],
658
            [
659
                'u__id' => '2',
660
                'u__status' => 'developer',
661
                'sclr0' => 'JWAGE',
662
                'p__phonenumber' => '91',
663
                'a__id' => '4',
664
                'a__topic' => 'PHP7',
665
            ],
666
        ];
667
668
        $stmt     = new HydratorMockStatement($resultSet);
669
        $hydrator = new ObjectHydrator($this->em);
670
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
671
672
        self::assertCount(2, $result);
673
674
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

674
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
675
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

675
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
676
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

676
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
677
678
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
679
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
680
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
681
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
682
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles);
683
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[0]);
684
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[1]);
685
686
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
687
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
688
        self::assertInstanceOf(CmsPhonenumber::class, $result[1][$userEntityKey]->phonenumbers[0]);
689
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[0]);
690
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[1]);
691
    }
692
693
    /**
694
     * SELECT u, p, UPPER(u.name) nameUpper, a, c
695
     *   FROM User u
696
     *   JOIN u.phonenumbers p
697
     *   JOIN u.articles a
698
     *   LEFT JOIN a.comments c
699
     *
700
     * @dataProvider provideDataForUserEntityResult
701
     */
702
    public function testMixedQueryMultipleDeepMixedFetchJoin($userEntityKey) : void
703
    {
704
        $rsm = new ResultSetMapping();
705
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
706
        $rsm->addJoinedEntityResult(
707
            CmsPhonenumber::class,
708
            'p',
709
            'u',
710
            'phonenumbers'
711
        );
712
        $rsm->addJoinedEntityResult(
713
            CmsArticle::class,
714
            'a',
715
            'u',
716
            'articles'
717
        );
718
        $rsm->addJoinedEntityResult(
719
            CmsComment::class,
720
            'c',
721
            'a',
722
            'comments'
723
        );
724
        $rsm->addFieldResult('u', 'u__id', 'id');
725
        $rsm->addFieldResult('u', 'u__status', 'status');
726
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
727
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
728
        $rsm->addFieldResult('a', 'a__id', 'id');
729
        $rsm->addFieldResult('a', 'a__topic', 'topic');
730
        $rsm->addFieldResult('c', 'c__id', 'id');
731
        $rsm->addFieldResult('c', 'c__topic', 'topic');
732
733
        // Faked result set
734
        $resultSet = [
735
            //row1
736
            [
737
                'u__id' => '1',
738
                'u__status' => 'developer',
739
                'sclr0' => 'ROMANB',
740
                'p__phonenumber' => '42',
741
                'a__id' => '1',
742
                'a__topic' => 'Getting things done!',
743
                'c__id' => '1',
744
                'c__topic' => 'First!',
745
            ],
746
            [
747
                'u__id' => '1',
748
                'u__status' => 'developer',
749
                'sclr0' => 'ROMANB',
750
                'p__phonenumber' => '43',
751
                'a__id' => '1',
752
                'a__topic' => 'Getting things done!',
753
                'c__id' => '1',
754
                'c__topic' => 'First!',
755
            ],
756
            [
757
                'u__id' => '1',
758
                'u__status' => 'developer',
759
                'sclr0' => 'ROMANB',
760
                'p__phonenumber' => '42',
761
                'a__id' => '2',
762
                'a__topic' => 'ZendCon',
763
                'c__id' => null,
764
                'c__topic' => null,
765
            ],
766
            [
767
                'u__id' => '1',
768
                'u__status' => 'developer',
769
                'sclr0' => 'ROMANB',
770
                'p__phonenumber' => '43',
771
                'a__id' => '2',
772
                'a__topic' => 'ZendCon',
773
                'c__id' => null,
774
                'c__topic' => null,
775
            ],
776
            [
777
                'u__id' => '2',
778
                'u__status' => 'developer',
779
                'sclr0' => 'JWAGE',
780
                'p__phonenumber' => '91',
781
                'a__id' => '3',
782
                'a__topic' => 'LINQ',
783
                'c__id' => null,
784
                'c__topic' => null,
785
            ],
786
            [
787
                'u__id' => '2',
788
                'u__status' => 'developer',
789
                'sclr0' => 'JWAGE',
790
                'p__phonenumber' => '91',
791
                'a__id' => '4',
792
                'a__topic' => 'PHP7',
793
                'c__id' => null,
794
                'c__topic' => null,
795
            ],
796
        ];
797
798
        $stmt     = new HydratorMockStatement($resultSet);
799
        $hydrator = new ObjectHydrator($this->em);
800
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
801
802
        self::assertCount(2, $result);
803
804
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

804
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
805
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

805
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
806
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

806
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
807
808
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
809
        self::assertInstanceOf(CmsUser::class, $result[1][$userEntityKey]);
810
811
        // phonenumbers
812
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->phonenumbers);
813
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[0]);
814
        self::assertInstanceOf(CmsPhonenumber::class, $result[0][$userEntityKey]->phonenumbers[1]);
815
816
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->phonenumbers);
817
        self::assertInstanceOf(CmsPhonenumber::class, $result[1][$userEntityKey]->phonenumbers[0]);
818
819
        // articles
820
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles);
821
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[0]);
822
        self::assertInstanceOf(CmsArticle::class, $result[0][$userEntityKey]->articles[1]);
823
824
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[0]);
825
        self::assertInstanceOf(CmsArticle::class, $result[1][$userEntityKey]->articles[1]);
826
827
        // article comments
828
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles[0]->comments);
829
        self::assertInstanceOf(CmsComment::class, $result[0][$userEntityKey]->articles[0]->comments[0]);
830
831
        // empty comment collections
832
        self::assertInstanceOf(PersistentCollection::class, $result[0][$userEntityKey]->articles[1]->comments);
833
        self::assertCount(0, $result[0][$userEntityKey]->articles[1]->comments);
834
835
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->articles[0]->comments);
836
        self::assertCount(0, $result[1][$userEntityKey]->articles[0]->comments);
837
        self::assertInstanceOf(PersistentCollection::class, $result[1][$userEntityKey]->articles[1]->comments);
838
        self::assertCount(0, $result[1][$userEntityKey]->articles[1]->comments);
839
    }
840
841
    /**
842
     * Tests that the hydrator does not rely on a particular order of the rows
843
     * in the result set.
844
     *
845
     * DQL:
846
     * select c, b from Doctrine\Tests\Models\Forum\ForumCategory c inner join c.boards b
847
     * order by c.position asc, b.position asc
848
     *
849
     * Checks whether the boards are correctly assigned to the categories.
850
     *
851
     * The 'evil' result set that confuses the object population is displayed below.
852
     *
853
     * c.id  | c.position | c.name   | boardPos | b.id | b.category_id (just for clarity)
854
     *  1    | 0          | First    | 0        |   1  | 1
855
     *  2    | 0          | Second   | 0        |   2  | 2   <--
856
     *  1    | 0          | First    | 1        |   3  | 1
857
     *  1    | 0          | First    | 2        |   4  | 1
858
     */
859
    public function testEntityQueryCustomResultSetOrder() : void
860
    {
861
        $rsm = new ResultSetMapping();
862
        $rsm->addEntityResult(ForumCategory::class, 'c');
863
        $rsm->addJoinedEntityResult(
864
            ForumBoard::class,
865
            'b',
866
            'c',
867
            'boards'
868
        );
869
        $rsm->addFieldResult('c', 'c__id', 'id');
870
        $rsm->addFieldResult('c', 'c__position', 'position');
871
        $rsm->addFieldResult('c', 'c__name', 'name');
872
        $rsm->addFieldResult('b', 'b__id', 'id');
873
        $rsm->addFieldResult('b', 'b__position', 'position');
874
875
        // Faked result set
876
        $resultSet = [
877
            [
878
                'c__id' => '1',
879
                'c__position' => '0',
880
                'c__name' => 'First',
881
                'b__id' => '1',
882
                'b__position' => '0',
883
                //'b__category_id' => '1'
884
            ],
885
            [
886
                'c__id' => '2',
887
                'c__position' => '0',
888
                'c__name' => 'Second',
889
                'b__id' => '2',
890
                'b__position' => '0',
891
                //'b__category_id' => '2'
892
            ],
893
            [
894
                'c__id' => '1',
895
                'c__position' => '0',
896
                'c__name' => 'First',
897
                'b__id' => '3',
898
                'b__position' => '1',
899
                //'b__category_id' => '1'
900
            ],
901
            [
902
                'c__id' => '1',
903
                'c__position' => '0',
904
                'c__name' => 'First',
905
                'b__id' => '4',
906
                'b__position' => '2',
907
                //'b__category_id' => '1'
908
            ],
909
        ];
910
911
        $stmt     = new HydratorMockStatement($resultSet);
912
        $hydrator = new ObjectHydrator($this->em);
913
        /** @var ForumCategory[] $result */
914
        $result = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
915
916
        self::assertCount(2, $result);
917
918
        self::assertInstanceOf(ForumCategory::class, $result[0]);
919
        self::assertInstanceOf(ForumCategory::class, $result[1]);
920
921
        self::assertNotSame($result[0], $result[1]);
922
923
        self::assertEquals(1, $result[0]->getId());
924
        self::assertEquals(2, $result[1]->getId());
925
926
        self::assertObjectHasAttribute('boards', $result[0]);
927
        self::assertCount(3, $result[0]->boards);
928
929
        self::assertObjectHasAttribute('boards', $result[1]);
930
        self::assertCount(1, $result[1]->boards);
931
    }
932
933
    /**
934
     * SELECT PARTIAL u.{id,name}
935
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
936
     *
937
     * @group DDC-644
938
     */
939
    public function testSkipUnknownColumns() : void
940
    {
941
        $rsm = new ResultSetMapping();
942
        $rsm->addEntityResult(CmsUser::class, 'u');
943
        $rsm->addFieldResult('u', 'u__id', 'id');
944
        $rsm->addFieldResult('u', 'u__name', 'name');
945
946
        // Faked result set
947
        $resultSet = [
948
            [
949
                'u__id' => '1',
950
                'u__name' => 'romanb',
951
                'foo' => 'bar', // unknown!
952
            ],
953
        ];
954
955
        $stmt     = new HydratorMockStatement($resultSet);
956
        $hydrator = new ObjectHydrator($this->em);
957
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
958
959
        self::assertCount(1, $result);
960
        self::assertInstanceOf(CmsUser::class, $result[0]);
961
    }
962
963
    /**
964
     * SELECT u.id, u.name
965
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
966
     *
967
     * @dataProvider provideDataForUserEntityResult
968
     */
969
    public function testScalarQueryWithoutResultVariables($userEntityKey) : void
970
    {
971
        $rsm = new ResultSetMapping();
972
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
973
        $rsm->addScalarResult('sclr0', 'id', Type::getType('integer'));
974
        $rsm->addScalarResult('sclr1', 'name', Type::getType('string'));
975
976
        // Faked result set
977
        $resultSet = [
978
            [
979
                'sclr0' => '1',
980
                'sclr1' => 'romanb',
981
            ],
982
            [
983
                'sclr0' => '2',
984
                'sclr1' => 'jwage',
985
            ],
986
        ];
987
988
        $stmt     = new HydratorMockStatement($resultSet);
989
        $hydrator = new ObjectHydrator($this->em);
990
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
991
992
        self::assertCount(2, $result);
993
994
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

994
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
995
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

995
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
996
997
        self::assertEquals(1, $result[0]['id']);
998
        self::assertEquals('romanb', $result[0]['name']);
999
1000
        self::assertEquals(2, $result[1]['id']);
1001
        self::assertEquals('jwage', $result[1]['name']);
1002
    }
1003
1004
    /**
1005
     * SELECT p
1006
     *   FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p
1007
     */
1008
    public function testCreatesProxyForLazyLoadingWithForeignKeys() : void
1009
    {
1010
        $rsm = new ResultSetMapping();
1011
        $rsm->addEntityResult(ECommerceProduct::class, 'p');
1012
        $rsm->addFieldResult('p', 'p__id', 'id');
1013
        $rsm->addFieldResult('p', 'p__name', 'name');
1014
        $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id', false, Type::getType('integer'));
1015
1016
        // Faked result set
1017
        $resultSet = [
1018
            [
1019
                'p__id' => '1',
1020
                'p__name' => 'Doctrine Book',
1021
                'p__shipping_id' => 42,
1022
            ],
1023
        ];
1024
1025
        $proxyInstance = (new LazyLoadingGhostFactory(new Configuration()))
1026
            ->createProxy(ECommerceShipping::class, static function () {
1027
                self::fail('Proxy is not supposed to be lazy-loaded');
1028
            });
1029
1030
        // mocking the proxy factory
1031
        $proxyFactory = $this->createMock(ProxyFactory::class);
1032
1033
        $proxyFactory
1034
            ->expects(self::once())
1035
            ->method('getProxy')
1036
            ->with($this->em->getClassMetadata(ECommerceShipping::class), ['id' => 42])
1037
            ->willReturn($proxyInstance);
1038
1039
        $this->em->setProxyFactory($proxyFactory);
1040
1041
        // configuring lazy loading
1042
        $metadata = $this->em->getClassMetadata(ECommerceProduct::class);
1043
        $metadata->getProperty('shipping')->setFetchMode(FetchMode::LAZY);
0 ignored issues
show
Bug introduced by
The method getProperty() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. ( Ignorable by Annotation )

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

1043
        $metadata->/** @scrutinizer ignore-call */ 
1044
                   getProperty('shipping')->setFetchMode(FetchMode::LAZY);

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...
1044
1045
        $stmt     = new HydratorMockStatement($resultSet);
1046
        $hydrator = new ObjectHydrator($this->em);
1047
        $result   = $hydrator->hydrateAll($stmt, $rsm);
1048
1049
        self::assertCount(1, $result);
1050
1051
        self::assertInstanceOf(ECommerceProduct::class, $result[0]);
1052
    }
1053
1054
    /**
1055
     * SELECT p AS product
1056
     *   FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p
1057
     */
1058
    public function testCreatesProxyForLazyLoadingWithForeignKeysWithAliasedProductEntity() : void
1059
    {
1060
        $rsm = new ResultSetMapping();
1061
        $rsm->addEntityResult(ECommerceProduct::class, 'p', 'product');
1062
        $rsm->addFieldResult('p', 'p__id', 'id');
1063
        $rsm->addFieldResult('p', 'p__name', 'name');
1064
        $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id', false, Type::getType('integer'));
1065
1066
        // Faked result set
1067
        $resultSet = [
1068
            [
1069
                'p__id' => '1',
1070
                'p__name' => 'Doctrine Book',
1071
                'p__shipping_id' => 42,
1072
            ],
1073
        ];
1074
1075
        $proxyInstance = (new LazyLoadingGhostFactory(new Configuration()))
1076
            ->createProxy(ECommerceShipping::class, static function () {
1077
                self::fail('Proxy is not supposed to be lazy-loaded');
1078
            });
1079
1080
        // mocking the proxy factory
1081
        $proxyFactory = $this
1082
            ->getMockBuilder(ProxyFactory::class)
1083
            ->disableOriginalConstructor()
1084
            ->getMock();
1085
1086
        $proxyFactory
1087
            ->expects(self::once())
1088
            ->method('getProxy')
1089
            ->with($this->em->getClassMetadata(ECommerceShipping::class), ['id' => 42])
1090
            ->willReturn($proxyInstance);
1091
1092
        $this->em->setProxyFactory($proxyFactory);
1093
1094
        // configuring lazy loading
1095
        $metadata = $this->em->getClassMetadata(ECommerceProduct::class);
1096
        $metadata->getProperty('shipping')->setFetchMode(FetchMode::LAZY);
1097
1098
        $stmt     = new HydratorMockStatement($resultSet);
1099
        $hydrator = new ObjectHydrator($this->em);
1100
        $result   = $hydrator->hydrateAll($stmt, $rsm);
1101
1102
        self::assertCount(1, $result);
1103
1104
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

1104
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1105
        self::assertInstanceOf(ECommerceProduct::class, $result[0]['product']);
1106
    }
1107
1108
    /**
1109
     * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, topic}, PARTIAL c.{id, topic}
1110
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1111
     *   LEFT JOIN u.articles a
1112
     *   LEFT JOIN a.comments c
1113
     */
1114
    public function testChainedJoinWithEmptyCollections() : void
1115
    {
1116
        $rsm = new ResultSetMapping();
1117
        $rsm->addEntityResult(CmsUser::class, 'u');
1118
        $rsm->addJoinedEntityResult(
1119
            CmsArticle::class,
1120
            'a',
1121
            'u',
1122
            'articles'
1123
        );
1124
        $rsm->addJoinedEntityResult(
1125
            CmsComment::class,
1126
            'c',
1127
            'a',
1128
            'comments'
1129
        );
1130
        $rsm->addFieldResult('u', 'u__id', 'id');
1131
        $rsm->addFieldResult('u', 'u__status', 'status');
1132
        $rsm->addFieldResult('a', 'a__id', 'id');
1133
        $rsm->addFieldResult('a', 'a__topic', 'topic');
1134
        $rsm->addFieldResult('c', 'c__id', 'id');
1135
        $rsm->addFieldResult('c', 'c__topic', 'topic');
1136
1137
        // Faked result set
1138
        $resultSet = [
1139
            //row1
1140
            [
1141
                'u__id' => '1',
1142
                'u__status' => 'developer',
1143
                'a__id' => null,
1144
                'a__topic' => null,
1145
                'c__id' => null,
1146
                'c__topic' => null,
1147
            ],
1148
            [
1149
                'u__id' => '2',
1150
                'u__status' => 'developer',
1151
                'a__id' => null,
1152
                'a__topic' => null,
1153
                'c__id' => null,
1154
                'c__topic' => null,
1155
            ],
1156
        ];
1157
1158
        $stmt     = new HydratorMockStatement($resultSet);
1159
        $hydrator = new ObjectHydrator($this->em);
1160
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1161
1162
        self::assertCount(2, $result);
1163
1164
        self::assertInstanceOf(CmsUser::class, $result[0]);
1165
        self::assertInstanceOf(CmsUser::class, $result[1]);
1166
1167
        self::assertEquals(0, $result[0]->articles->count());
1168
        self::assertEquals(0, $result[1]->articles->count());
1169
    }
1170
1171
    /**
1172
     * SELECT PARTIAL u.{id, status} AS user, PARTIAL a.{id, topic}, PARTIAL c.{id, topic}
1173
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1174
     *   LEFT JOIN u.articles a
1175
     *   LEFT JOIN a.comments c
1176
     */
1177
    public function testChainedJoinWithEmptyCollectionsWithAliasedUserEntity() : void
1178
    {
1179
        $rsm = new ResultSetMapping();
1180
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1181
        $rsm->addJoinedEntityResult(
1182
            CmsArticle::class,
1183
            'a',
1184
            'u',
1185
            'articles'
1186
        );
1187
        $rsm->addJoinedEntityResult(
1188
            CmsComment::class,
1189
            'c',
1190
            'a',
1191
            'comments'
1192
        );
1193
        $rsm->addFieldResult('u', 'u__id', 'id');
1194
        $rsm->addFieldResult('u', 'u__status', 'status');
1195
        $rsm->addFieldResult('a', 'a__id', 'id');
1196
        $rsm->addFieldResult('a', 'a__topic', 'topic');
1197
        $rsm->addFieldResult('c', 'c__id', 'id');
1198
        $rsm->addFieldResult('c', 'c__topic', 'topic');
1199
1200
        // Faked result set
1201
        $resultSet = [
1202
            //row1
1203
            [
1204
                'u__id' => '1',
1205
                'u__status' => 'developer',
1206
                'a__id' => null,
1207
                'a__topic' => null,
1208
                'c__id' => null,
1209
                'c__topic' => null,
1210
            ],
1211
            [
1212
                'u__id' => '2',
1213
                'u__status' => 'developer',
1214
                'a__id' => null,
1215
                'a__topic' => null,
1216
                'c__id' => null,
1217
                'c__topic' => null,
1218
            ],
1219
        ];
1220
1221
        $stmt     = new HydratorMockStatement($resultSet);
1222
        $hydrator = new ObjectHydrator($this->em);
1223
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1224
1225
        self::assertCount(2, $result);
1226
1227
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

1227
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1228
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1229
1230
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

1230
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1231
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
1232
1233
        self::assertEquals(0, $result[0]['user']->articles->count());
1234
        self::assertEquals(0, $result[1]['user']->articles->count());
1235
    }
1236
1237
    /**
1238
     * SELECT PARTIAL u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic
1239
     *   FROM CmsUser u
1240
     *   LEFT JOIN u.articles a
1241
     *   LEFT JOIN a.comments c
1242
     *
1243
     * @todo Figure it out why this test is commented out and provide a better description in docblock
1244
     * @group bubu
1245
     * @dataProvider provideDataForUserEntityResult
1246
     */
1247
    /*public function testChainedJoinWithScalars($userEntityKey) : void
1248
    {
1249
        $rsm = new ResultSetMapping;
1250
        $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
1251
        $rsm->addFieldResult('u', 'u__id', 'id');
1252
        $rsm->addFieldResult('u', 'u__status', 'status');
1253
        $rsm->addScalarResult('a__id', 'id', Type::getType('integer'));
1254
        $rsm->addScalarResult('a__topic', 'topic', Type::getType('string'));
1255
        $rsm->addScalarResult('c__id', 'cid', Type::getType('integer'));
1256
        $rsm->addScalarResult('c__topic', 'ctopic', Type::getType('string'));
1257
1258
        // Faked result set
1259
        $resultSet = array(
1260
            //row1
1261
            array(
1262
                'u__id' => '1',
1263
                'u__status' => 'developer',
1264
                'a__id' => '1',
1265
                'a__topic' => 'The First',
1266
                'c__id' => '1',
1267
                'c__topic' => 'First Comment'
1268
            ),
1269
            array(
1270
                'u__id' => '1',
1271
                'u__status' => 'developer',
1272
                'a__id' => '1',
1273
                'a__topic' => 'The First',
1274
                'c__id' => '2',
1275
                'c__topic' => 'Second Comment'
1276
            ),
1277
            array(
1278
                'u__id' => '1',
1279
                'u__status' => 'developer',
1280
                'a__id' => '42',
1281
                'a__topic' => 'The Answer',
1282
                'c__id' => null,
1283
                'c__topic' => null
1284
            ),
1285
        );
1286
1287
        $stmt     = new HydratorMockStatement($resultSet);
1288
        $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->em);
1289
        $result   = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
1290
1291
        \Doctrine\Common\Util\Debug::dump($result, 3);
1292
1293
        self::assertCount(1, $result);
1294
1295
        self::assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); // User object
1296
        self::assertEquals(42, $result[0]['id']);
1297
        self::assertEquals('The First', $result[0]['topic']);
1298
        self::assertEquals(1, $result[0]['cid']);
1299
        self::assertEquals('First Comment', $result[0]['ctopic']);
1300
    }*/
1301
1302
    /**
1303
     * SELECT PARTIAL u.{id, name}
1304
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1305
     */
1306
    public function testResultIteration() : void
1307
    {
1308
        $rsm = new ResultSetMapping();
1309
        $rsm->addEntityResult(CmsUser::class, 'u');
1310
        $rsm->addFieldResult('u', 'u__id', 'id');
1311
        $rsm->addFieldResult('u', 'u__name', 'name');
1312
1313
        // Faked result set
1314
        $resultSet = [
1315
            [
1316
                'u__id' => '1',
1317
                'u__name' => 'romanb',
1318
            ],
1319
            [
1320
                'u__id' => '2',
1321
                'u__name' => 'jwage',
1322
            ],
1323
        ];
1324
1325
        $stmt           = new HydratorMockStatement($resultSet);
1326
        $hydrator       = new ObjectHydrator($this->em);
1327
        $iterableResult = $hydrator->iterate($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1328
        $rowNum         = 0;
1329
1330
        while (($row = $iterableResult->next()) !== false) {
1331
            self::assertCount(1, $row);
1332
            self::assertInstanceOf(CmsUser::class, $row[0]);
1333
1334
            if ($rowNum === 0) {
1335
                self::assertEquals(1, $row[0]->id);
1336
                self::assertEquals('romanb', $row[0]->name);
1337
            }
1338
1339
            if ($rowNum === 1) {
1340
                self::assertEquals(2, $row[0]->id);
1341
                self::assertEquals('jwage', $row[0]->name);
1342
            }
1343
1344
            ++$rowNum;
1345
        }
1346
    }
1347
1348
    /**
1349
     * SELECT PARTIAL u.{id, name}
1350
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1351
     */
1352
    public function testResultIterationWithAliasedUserEntity() : void
1353
    {
1354
        $rsm = new ResultSetMapping();
1355
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1356
        $rsm->addFieldResult('u', 'u__id', 'id');
1357
        $rsm->addFieldResult('u', 'u__name', 'name');
1358
1359
        // Faked result set
1360
        $resultSet = [
1361
            [
1362
                'u__id' => '1',
1363
                'u__name' => 'romanb',
1364
            ],
1365
            [
1366
                'u__id' => '2',
1367
                'u__name' => 'jwage',
1368
            ],
1369
        ];
1370
1371
        $stmt           = new HydratorMockStatement($resultSet);
1372
        $hydrator       = new ObjectHydrator($this->em);
1373
        $iterableResult = $hydrator->iterate($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1374
        $rowNum         = 0;
1375
1376
        while (($row = $iterableResult->next()) !== false) {
1377
            self::assertCount(1, $row);
1378
            self::assertArrayHasKey(0, $row);
1379
            self::assertArrayHasKey('user', $row[0]);
1380
            self::assertInstanceOf(CmsUser::class, $row[0]['user']);
1381
1382
            if ($rowNum === 0) {
1383
                self::assertEquals(1, $row[0]['user']->id);
1384
                self::assertEquals('romanb', $row[0]['user']->name);
1385
            }
1386
1387
            if ($rowNum === 1) {
1388
                self::assertEquals(2, $row[0]['user']->id);
1389
                self::assertEquals('jwage', $row[0]['user']->name);
1390
            }
1391
1392
            ++$rowNum;
1393
        }
1394
    }
1395
1396
    /**
1397
     * Checks if multiple joined multiple-valued collections is hydrated correctly.
1398
     *
1399
     * SELECT PARTIAL u.{id, status}, PARTIAL g.{id, name}, PARTIAL p.{phonenumber}
1400
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1401
     *
1402
     * @group DDC-809
1403
     */
1404
    public function testManyToManyHydration() : void
1405
    {
1406
        $rsm = new ResultSetMapping();
1407
        $rsm->addEntityResult(CmsUser::class, 'u');
1408
        $rsm->addFieldResult('u', 'u__id', 'id');
1409
        $rsm->addFieldResult('u', 'u__name', 'name');
1410
        $rsm->addJoinedEntityResult(CmsGroup::class, 'g', 'u', 'groups');
1411
        $rsm->addFieldResult('g', 'g__id', 'id');
1412
        $rsm->addFieldResult('g', 'g__name', 'name');
1413
        $rsm->addJoinedEntityResult(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
1414
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1415
1416
        // Faked result set
1417
        $resultSet = [
1418
            [
1419
                'u__id' => '1',
1420
                'u__name' => 'romanb',
1421
                'g__id' => '3',
1422
                'g__name' => 'TestGroupB',
1423
                'p__phonenumber' => 1111,
1424
            ],
1425
            [
1426
                'u__id' => '1',
1427
                'u__name' => 'romanb',
1428
                'g__id' => '5',
1429
                'g__name' => 'TestGroupD',
1430
                'p__phonenumber' => 1111,
1431
            ],
1432
            [
1433
                'u__id' => '1',
1434
                'u__name' => 'romanb',
1435
                'g__id' => '3',
1436
                'g__name' => 'TestGroupB',
1437
                'p__phonenumber' => 2222,
1438
            ],
1439
            [
1440
                'u__id' => '1',
1441
                'u__name' => 'romanb',
1442
                'g__id' => '5',
1443
                'g__name' => 'TestGroupD',
1444
                'p__phonenumber' => 2222,
1445
            ],
1446
            [
1447
                'u__id' => '2',
1448
                'u__name' => 'jwage',
1449
                'g__id' => '2',
1450
                'g__name' => 'TestGroupA',
1451
                'p__phonenumber' => 3333,
1452
            ],
1453
            [
1454
                'u__id' => '2',
1455
                'u__name' => 'jwage',
1456
                'g__id' => '3',
1457
                'g__name' => 'TestGroupB',
1458
                'p__phonenumber' => 3333,
1459
            ],
1460
            [
1461
                'u__id' => '2',
1462
                'u__name' => 'jwage',
1463
                'g__id' => '4',
1464
                'g__name' => 'TestGroupC',
1465
                'p__phonenumber' => 3333,
1466
            ],
1467
            [
1468
                'u__id' => '2',
1469
                'u__name' => 'jwage',
1470
                'g__id' => '5',
1471
                'g__name' => 'TestGroupD',
1472
                'p__phonenumber' => 3333,
1473
            ],
1474
            [
1475
                'u__id' => '2',
1476
                'u__name' => 'jwage',
1477
                'g__id' => '2',
1478
                'g__name' => 'TestGroupA',
1479
                'p__phonenumber' => 4444,
1480
            ],
1481
            [
1482
                'u__id' => '2',
1483
                'u__name' => 'jwage',
1484
                'g__id' => '3',
1485
                'g__name' => 'TestGroupB',
1486
                'p__phonenumber' => 4444,
1487
            ],
1488
            [
1489
                'u__id' => '2',
1490
                'u__name' => 'jwage',
1491
                'g__id' => '4',
1492
                'g__name' => 'TestGroupC',
1493
                'p__phonenumber' => 4444,
1494
            ],
1495
            [
1496
                'u__id' => '2',
1497
                'u__name' => 'jwage',
1498
                'g__id' => '5',
1499
                'g__name' => 'TestGroupD',
1500
                'p__phonenumber' => 4444,
1501
            ],
1502
        ];
1503
1504
        $stmt     = new HydratorMockStatement($resultSet);
1505
        $hydrator = new ObjectHydrator($this->em);
1506
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1507
1508
        self::assertCount(2, $result);
1509
1510
        self::assertContainsOnly(CmsUser::class, $result);
1511
1512
        self::assertCount(2, $result[0]->groups);
1513
        self::assertCount(2, $result[0]->phonenumbers);
1514
1515
        self::assertCount(4, $result[1]->groups);
1516
        self::assertCount(2, $result[1]->phonenumbers);
1517
    }
1518
1519
    /**
1520
     * Checks if multiple joined multiple-valued collections is hydrated correctly.
1521
     *
1522
     * SELECT PARTIAL u.{id, status} As user, PARTIAL g.{id, name}, PARTIAL p.{phonenumber}
1523
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1524
     *
1525
     * @group DDC-809
1526
     */
1527
    public function testManyToManyHydrationWithAliasedUserEntity() : void
1528
    {
1529
        $rsm = new ResultSetMapping();
1530
        $rsm->addEntityResult(CmsUser::class, 'u', 'user');
1531
        $rsm->addFieldResult('u', 'u__id', 'id');
1532
        $rsm->addFieldResult('u', 'u__name', 'name');
1533
        $rsm->addJoinedEntityResult(CmsGroup::class, 'g', 'u', 'groups');
1534
        $rsm->addFieldResult('g', 'g__id', 'id');
1535
        $rsm->addFieldResult('g', 'g__name', 'name');
1536
        $rsm->addJoinedEntityResult(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
1537
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1538
1539
        // Faked result set
1540
        $resultSet = [
1541
            [
1542
                'u__id' => '1',
1543
                'u__name' => 'romanb',
1544
                'g__id' => '3',
1545
                'g__name' => 'TestGroupB',
1546
                'p__phonenumber' => 1111,
1547
            ],
1548
            [
1549
                'u__id' => '1',
1550
                'u__name' => 'romanb',
1551
                'g__id' => '5',
1552
                'g__name' => 'TestGroupD',
1553
                'p__phonenumber' => 1111,
1554
            ],
1555
            [
1556
                'u__id' => '1',
1557
                'u__name' => 'romanb',
1558
                'g__id' => '3',
1559
                'g__name' => 'TestGroupB',
1560
                'p__phonenumber' => 2222,
1561
            ],
1562
            [
1563
                'u__id' => '1',
1564
                'u__name' => 'romanb',
1565
                'g__id' => '5',
1566
                'g__name' => 'TestGroupD',
1567
                'p__phonenumber' => 2222,
1568
            ],
1569
            [
1570
                'u__id' => '2',
1571
                'u__name' => 'jwage',
1572
                'g__id' => '2',
1573
                'g__name' => 'TestGroupA',
1574
                'p__phonenumber' => 3333,
1575
            ],
1576
            [
1577
                'u__id' => '2',
1578
                'u__name' => 'jwage',
1579
                'g__id' => '3',
1580
                'g__name' => 'TestGroupB',
1581
                'p__phonenumber' => 3333,
1582
            ],
1583
            [
1584
                'u__id' => '2',
1585
                'u__name' => 'jwage',
1586
                'g__id' => '4',
1587
                'g__name' => 'TestGroupC',
1588
                'p__phonenumber' => 3333,
1589
            ],
1590
            [
1591
                'u__id' => '2',
1592
                'u__name' => 'jwage',
1593
                'g__id' => '5',
1594
                'g__name' => 'TestGroupD',
1595
                'p__phonenumber' => 3333,
1596
            ],
1597
            [
1598
                'u__id' => '2',
1599
                'u__name' => 'jwage',
1600
                'g__id' => '2',
1601
                'g__name' => 'TestGroupA',
1602
                'p__phonenumber' => 4444,
1603
            ],
1604
            [
1605
                'u__id' => '2',
1606
                'u__name' => 'jwage',
1607
                'g__id' => '3',
1608
                'g__name' => 'TestGroupB',
1609
                'p__phonenumber' => 4444,
1610
            ],
1611
            [
1612
                'u__id' => '2',
1613
                'u__name' => 'jwage',
1614
                'g__id' => '4',
1615
                'g__name' => 'TestGroupC',
1616
                'p__phonenumber' => 4444,
1617
            ],
1618
            [
1619
                'u__id' => '2',
1620
                'u__name' => 'jwage',
1621
                'g__id' => '5',
1622
                'g__name' => 'TestGroupD',
1623
                'p__phonenumber' => 4444,
1624
            ],
1625
        ];
1626
1627
        $stmt     = new HydratorMockStatement($resultSet);
1628
        $hydrator = new ObjectHydrator($this->em);
1629
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1630
1631
        self::assertCount(2, $result);
1632
1633
        self::assertInternalType('array', $result[0]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

1633
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[0]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1634
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1635
        self::assertInternalType('array', $result[1]);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

1635
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result[1]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1636
        self::assertInstanceOf(CmsUser::class, $result[1]['user']);
1637
1638
        self::assertCount(2, $result[0]['user']->groups);
1639
        self::assertCount(2, $result[0]['user']->phonenumbers);
1640
1641
        self::assertCount(4, $result[1]['user']->groups);
1642
        self::assertCount(2, $result[1]['user']->phonenumbers);
1643
    }
1644
1645
    /**
1646
     * SELECT PARTIAL u.{id, status}, UPPER(u.name) as nameUpper
1647
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1648
     *
1649
     * @group DDC-1358
1650
     * @dataProvider provideDataForUserEntityResult
1651
     */
1652
    public function testMissingIdForRootEntity($userEntityKey) : void
1653
    {
1654
        $rsm = new ResultSetMapping();
1655
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1656
        $rsm->addFieldResult('u', 'u__id', 'id');
1657
        $rsm->addFieldResult('u', 'u__status', 'status');
1658
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1659
1660
        // Faked result set
1661
        $resultSet = [
1662
            //row1
1663
            [
1664
                'u__id' => '1',
1665
                'u__status' => 'developer',
1666
                'sclr0' => 'ROMANB',
1667
            ],
1668
            [
1669
                'u__id' => null,
1670
                'u__status' => null,
1671
                'sclr0' => 'ROMANB',
1672
            ],
1673
            [
1674
                'u__id' => '2',
1675
                'u__status' => 'developer',
1676
                'sclr0' => 'JWAGE',
1677
            ],
1678
            [
1679
                'u__id' => null,
1680
                'u__status' => null,
1681
                'sclr0' => 'JWAGE',
1682
            ],
1683
        ];
1684
1685
        $stmt     = new HydratorMockStatement($resultSet);
1686
        $hydrator = new ObjectHydrator($this->em);
1687
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1688
1689
        self::assertCount(4, $result, 'Should hydrate four results.');
1690
1691
        self::assertEquals('ROMANB', $result[0]['nameUpper']);
1692
        self::assertEquals('ROMANB', $result[1]['nameUpper']);
1693
        self::assertEquals('JWAGE', $result[2]['nameUpper']);
1694
        self::assertEquals('JWAGE', $result[3]['nameUpper']);
1695
1696
        self::assertInstanceOf(CmsUser::class, $result[0][$userEntityKey]);
1697
        self::assertNull($result[1][$userEntityKey]);
1698
1699
        self::assertInstanceOf(CmsUser::class, $result[2][$userEntityKey]);
1700
        self::assertNull($result[3][$userEntityKey]);
1701
    }
1702
1703
    /**
1704
     * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) AS nameUpper
1705
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1706
     *   LEFT JOIN u.phonenumbers u
1707
     *
1708
     * @group DDC-1358
1709
     * @dataProvider provideDataForUserEntityResult
1710
     */
1711
    public function testMissingIdForCollectionValuedChildEntity($userEntityKey) : void
1712
    {
1713
        $rsm = new ResultSetMapping();
1714
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1715
        $rsm->addJoinedEntityResult(
1716
            CmsPhonenumber::class,
1717
            'p',
1718
            'u',
1719
            'phonenumbers'
1720
        );
1721
        $rsm->addFieldResult('u', 'u__id', 'id');
1722
        $rsm->addFieldResult('u', 'u__status', 'status');
1723
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1724
        $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
1725
1726
        // Faked result set
1727
        $resultSet = [
1728
            //row1
1729
            [
1730
                'u__id' => '1',
1731
                'u__status' => 'developer',
1732
                'sclr0' => 'ROMANB',
1733
                'p__phonenumber' => '42',
1734
            ],
1735
            [
1736
                'u__id' => '1',
1737
                'u__status' => 'developer',
1738
                'sclr0' => 'ROMANB',
1739
                'p__phonenumber' => null,
1740
            ],
1741
            [
1742
                'u__id' => '2',
1743
                'u__status' => 'developer',
1744
                'sclr0' => 'JWAGE',
1745
                'p__phonenumber' => '91',
1746
            ],
1747
            [
1748
                'u__id' => '2',
1749
                'u__status' => 'developer',
1750
                'sclr0' => 'JWAGE',
1751
                'p__phonenumber' => null,
1752
            ],
1753
        ];
1754
1755
        $stmt     = new HydratorMockStatement($resultSet);
1756
        $hydrator = new ObjectHydrator($this->em);
1757
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1758
1759
        self::assertCount(2, $result);
1760
1761
        self::assertEquals(1, $result[0][$userEntityKey]->phonenumbers->count());
1762
        self::assertEquals(1, $result[1][$userEntityKey]->phonenumbers->count());
1763
    }
1764
1765
    /**
1766
     * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, city}, UPPER(u.name) AS nameUpper
1767
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1768
     *   JOIN u.address a
1769
     *
1770
     * @group DDC-1358
1771
     * @dataProvider provideDataForUserEntityResult
1772
     */
1773
    public function testMissingIdForSingleValuedChildEntity($userEntityKey) : void
1774
    {
1775
        $rsm = new ResultSetMapping();
1776
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1777
        $rsm->addJoinedEntityResult(
1778
            CmsAddress::class,
1779
            'a',
1780
            'u',
1781
            'address'
1782
        );
1783
        $rsm->addFieldResult('u', 'u__id', 'id');
1784
        $rsm->addFieldResult('u', 'u__status', 'status');
1785
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1786
        $rsm->addFieldResult('a', 'a__id', 'id');
1787
        $rsm->addFieldResult('a', 'a__city', 'city');
1788
        $rsm->addMetaResult('a', 'user_id', 'user_id', false, Type::getType('string'));
1789
1790
        // Faked result set
1791
        $resultSet = [
1792
            //row1
1793
            [
1794
                'u__id' => '1',
1795
                'u__status' => 'developer',
1796
                'sclr0' => 'ROMANB',
1797
                'a__id' => 1,
1798
                'a__city' => 'Berlin',
1799
            ],
1800
            [
1801
                'u__id' => '2',
1802
                'u__status' => 'developer',
1803
                'sclr0' => 'BENJAMIN',
1804
                'a__id' => null,
1805
                'a__city' => null,
1806
            ],
1807
        ];
1808
1809
        $stmt     = new HydratorMockStatement($resultSet);
1810
        $hydrator = new ObjectHydrator($this->em);
1811
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1812
1813
        self::assertCount(2, $result);
1814
1815
        self::assertInstanceOf(CmsAddress::class, $result[0][$userEntityKey]->address);
1816
        self::assertNull($result[1][$userEntityKey]->address);
1817
    }
1818
1819
    /**
1820
     * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
1821
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1822
     *        INDEX BY u.id
1823
     *
1824
     * @group DDC-1385
1825
     * @dataProvider provideDataForUserEntityResult
1826
     */
1827
    public function testIndexByAndMixedResult($userEntityKey) : void
1828
    {
1829
        $rsm = new ResultSetMapping();
1830
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1831
        $rsm->addFieldResult('u', 'u__id', 'id');
1832
        $rsm->addFieldResult('u', 'u__status', 'status');
1833
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1834
        $rsm->addIndexBy('u', 'id');
1835
1836
        // Faked result set
1837
        $resultSet = [
1838
            //row1
1839
            [
1840
                'u__id' => '1',
1841
                'u__status' => 'developer',
1842
                'sclr0' => 'ROMANB',
1843
            ],
1844
            [
1845
                'u__id' => '2',
1846
                'u__status' => 'developer',
1847
                'sclr0' => 'JWAGE',
1848
            ],
1849
        ];
1850
1851
        $stmt     = new HydratorMockStatement($resultSet);
1852
        $hydrator = new ObjectHydrator($this->em);
1853
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1854
1855
        self::assertCount(2, $result);
1856
1857
        self::assertArrayHasKey(1, $result);
1858
        self::assertEquals(1, $result[1][$userEntityKey]->id);
1859
1860
        self::assertArrayHasKey(2, $result);
1861
        self::assertEquals(2, $result[2][$userEntityKey]->id);
1862
    }
1863
1864
    /**
1865
     * SELECT UPPER(u.name) AS nameUpper
1866
     *   FROM Doctrine\Tests\Models\CMS\CmsUser u
1867
     *
1868
     * @group DDC-1385
1869
     * @dataProvider provideDataForUserEntityResult
1870
     */
1871
    public function testIndexByScalarsOnly($userEntityKey) : void
1872
    {
1873
        $rsm = new ResultSetMapping();
1874
        $rsm->addEntityResult(CmsUser::class, 'u', $userEntityKey ?: null);
1875
        $rsm->addScalarResult('sclr0', 'nameUpper', Type::getType('string'));
1876
        $rsm->addIndexByScalar('sclr0');
1877
1878
        // Faked result set
1879
        $resultSet = [
1880
            //row1
1881
            ['sclr0' => 'ROMANB'],
1882
            ['sclr0' => 'JWAGE'],
1883
        ];
1884
1885
        $stmt     = new HydratorMockStatement($resultSet);
1886
        $hydrator = new ObjectHydrator($this->em);
1887
        $result   = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
1888
1889
        self::assertEquals(
1890
            [
1891
                'ROMANB' => ['nameUpper' => 'ROMANB'],
1892
                'JWAGE'  => ['nameUpper' => 'JWAGE'],
1893
            ],
1894
            $result
1895
        );
1896
    }
1897
1898
    /**
1899
     * @group DDC-1470
1900
     * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
1901
     * @expectedExceptionMessage The meta mapping for the discriminator column "c_discr" is missing for "Doctrine\Tests\Models\Company\CompanyFixContract" using the DQL alias "c".
1902
     */
1903
    public function testMissingMetaMappingException() : void
1904
    {
1905
        $rsm = new ResultSetMapping();
1906
1907
        $rsm->addEntityResult(CompanyFixContract::class, 'c');
1908
        $rsm->addJoinedEntityResult(CompanyEmployee::class, 'e', 'c', 'salesPerson');
1909
        $rsm->addFieldResult('c', 'c__id', 'id');
1910
        $rsm->setDiscriminatorColumn('c', 'c_discr');
1911
1912
        $resultSet = [
1913
            [
1914
                'c__id'   => '1',
1915
                'c_discr' => 'fix',
1916
            ],
1917
        ];
1918
1919
        $stmt     = new HydratorMockStatement($resultSet);
1920
        $hydrator = new ObjectHydrator($this->em);
1921
        $hydrator->hydrateAll($stmt, $rsm);
1922
    }
1923
1924
    /**
1925
     * @group DDC-1470
1926
     * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
1927
     * @expectedExceptionMessage The discriminator column "discr" is missing for "Doctrine\Tests\Models\Company\CompanyEmployee" using the DQL alias "e".
1928
     */
1929
    public function testMissingDiscriminatorColumnException() : void
1930
    {
1931
        $rsm = new ResultSetMapping();
1932
1933
        $rsm->addEntityResult(CompanyFixContract::class, 'c');
1934
        $rsm->addJoinedEntityResult(CompanyEmployee::class, 'e', 'c', 'salesPerson');
1935
        $rsm->addFieldResult('c', 'c__id', 'id');
1936
        $rsm->addMetaResult('c', 'c_discr', 'discr', false, Type::getType('string'));
1937
        $rsm->setDiscriminatorColumn('c', 'c_discr');
1938
        $rsm->addFieldResult('e', 'e__id', 'id');
1939
        $rsm->addFieldResult('e', 'e__name', 'name');
1940
        $rsm->addMetaResult('e ', 'e_discr', 'discr', false, Type::getType('string'));
1941
        $rsm->setDiscriminatorColumn('e', 'e_discr');
1942
1943
        $resultSet = [
1944
            [
1945
                'c__id'   => '1',
1946
                'c_discr' => 'fix',
1947
                'e__id'   => '1',
1948
                'e__name' => 'Fabio B. Silva',
1949
            ],
1950
        ];
1951
1952
        $stmt     = new HydratorMockStatement($resultSet);
1953
        $hydrator = new ObjectHydrator($this->em);
1954
        $hydrator->hydrateAll($stmt, $rsm);
1955
    }
1956
1957
    /**
1958
     * @group DDC-3076
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
    public function testInvalidDiscriminatorValueException() : void
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 ObjectHydrator($this->em);
1982
        $hydrator->hydrateAll($stmt, $rsm);
1983
    }
1984
1985
    public function testFetchJoinCollectionValuedAssociationWithDefaultArrayValue() : void
1986
    {
1987
        $rsm = new ResultSetMapping();
1988
1989
        $rsm->addEntityResult(EntityWithArrayDefaultArrayValueM2M::class, 'e1');
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 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