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

417
        /** @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...
418
        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

418
        /** @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...
419
        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

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

481
        /** @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...
482
        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

482
        /** @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...
483
        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

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

561
        /** @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...
562
        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

562
        /** @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...
563
        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

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

675
        /** @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...
676
        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

676
        /** @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...
677
        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

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

805
        /** @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...
806
        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

806
        /** @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...
807
        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

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

995
        /** @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...
996
        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

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

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

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

1228
        /** @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...
1229
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1230
1231
        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

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

1634
        /** @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...
1635
        self::assertInstanceOf(CmsUser::class, $result[0]['user']);
1636
        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

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