Passed
Pull Request — master (#7878)
by
unknown
10:27
created

testConcreteClassInJoinedTableInheritanceSchemaWithRSMBuilderIsFine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Functional;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\DBAL\Types\Type as DBALType;
9
use Doctrine\ORM\AbstractQuery;
10
use Doctrine\ORM\Internal\Hydration\HydrationException;
11
use Doctrine\ORM\PersistentCollection;
12
use Doctrine\ORM\Query\Parameter;
13
use Doctrine\ORM\Query\ResultSetMapping;
14
use Doctrine\ORM\Query\ResultSetMappingBuilder;
15
use Doctrine\Tests\Models\CMS\CmsAddress;
16
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
17
use Doctrine\Tests\Models\CMS\CmsUser;
18
use Doctrine\Tests\Models\Company\CompanyAuction;
19
use Doctrine\Tests\Models\Company\CompanyContract;
20
use Doctrine\Tests\Models\Company\CompanyEvent;
21
use Doctrine\Tests\Models\Company\CompanyFixContract;
22
use Doctrine\Tests\Models\DDC3899\DDC3899FixContract;
23
use Doctrine\Tests\Models\DDC3899\DDC3899User;
24
use Doctrine\Tests\OrmFunctionalTestCase;
25
use InvalidArgumentException;
26
use ReflectionClass;
27
28
/**
29
 * NativeQueryTest
30
 */
31
class NativeQueryTest extends OrmFunctionalTestCase
32
{
33
    private $platform;
34
35
    protected function setUp() : void
36
    {
37
        $this->useModelSet('cms');
38
        $this->useModelSet('company');
39
40
        parent::setUp();
41
42
        $this->platform = $this->em->getConnection()->getDatabasePlatform();
43
    }
44
45
    public function testBasicNativeQuery() : void
46
    {
47
        $user = new CmsUser();
48
49
        $user->name     = 'Roman';
50
        $user->username = 'romanb';
51
        $user->status   = 'dev';
52
53
        $this->em->persist($user);
54
        $this->em->flush();
55
        $this->em->clear();
56
57
        $rsm = new ResultSetMapping();
58
59
        $rsm->addEntityResult(CmsUser::class, 'u');
60
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
61
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name');
62
63
        $query = $this->em->createNativeQuery('SELECT id, name FROM cms_users WHERE username = ?', $rsm);
64
65
        $query->setParameter(1, 'romanb');
66
67
        $users = $query->getResult();
68
69
        self::assertCount(1, $users);
70
        self::assertInstanceOf(CmsUser::class, $users[0]);
71
        self::assertEquals('Roman', $users[0]->name);
72
    }
73
74
    public function testBasicNativeQueryWithMetaResult() : void
75
    {
76
        $user = new CmsUser();
77
78
        $user->name     = 'Roman';
79
        $user->username = 'romanb';
80
        $user->status   = 'dev';
81
82
        $addr = new CmsAddress();
83
84
        $addr->country = 'germany';
85
        $addr->zip     = 10827;
86
        $addr->city    = 'Berlin';
87
88
        $user->setAddress($addr);
89
90
        $this->em->persist($user);
91
        $this->em->flush();
92
        $this->em->clear();
93
94
        $rsm = new ResultSetMapping();
95
96
        $rsm->addEntityResult(CmsAddress::class, 'a');
97
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('id'), 'id');
98
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country');
99
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip');
100
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city');
101
        $rsm->addMetaResult('a', $this->platform->getSQLResultCasing('user_id'), 'user_id', false, DBALType::getType('integer'));
102
103
        $query = $this->em->createNativeQuery('SELECT a.id, a.country, a.zip, a.city, a.user_id FROM cms_addresses a WHERE a.id = ?', $rsm);
104
105
        $query->setParameter(1, $addr->id);
106
107
        $addresses = $query->getResult();
108
109
        self::assertCount(1, $addresses);
110
        self::assertInstanceOf(CmsAddress::class, $addresses[0]);
111
        self::assertEquals($addr->country, $addresses[0]->country);
112
        self::assertEquals($addr->zip, $addresses[0]->zip);
113
        self::assertEquals($addr->city, $addresses[0]->city);
114
        self::assertEquals($addr->street, $addresses[0]->street);
115
        self::assertInstanceOf(CmsUser::class, $addresses[0]->user);
116
    }
117
118
    public function testJoinedOneToManyNativeQuery() : void
119
    {
120
        $user = new CmsUser();
121
122
        $user->name     = 'Roman';
123
        $user->username = 'romanb';
124
        $user->status   = 'dev';
125
126
        $phone = new CmsPhonenumber();
127
128
        $phone->phonenumber = 424242;
129
130
        $user->addPhonenumber($phone);
131
132
        $this->em->persist($user);
133
        $this->em->flush();
134
        $this->em->clear();
135
136
        $rsm = new ResultSetMapping();
137
138
        $rsm->addEntityResult(CmsUser::class, 'u');
139
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
140
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name');
141
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status');
142
        $rsm->addJoinedEntityResult(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
143
        $rsm->addFieldResult('p', $this->platform->getSQLResultCasing('phonenumber'), 'phonenumber');
144
145
        $query = $this->em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm);
146
147
        $query->setParameter(1, 'romanb');
148
149
        $users = $query->getResult();
150
151
        self::assertCount(1, $users);
152
        self::assertInstanceOf(CmsUser::class, $users[0]);
153
        self::assertEquals('Roman', $users[0]->name);
154
        self::assertInstanceOf(PersistentCollection::class, $users[0]->getPhonenumbers());
155
        self::assertTrue($users[0]->getPhonenumbers()->isInitialized());
156
        self::assertCount(1, $users[0]->getPhonenumbers());
157
158
        $phones = $users[0]->getPhonenumbers();
159
160
        self::assertEquals(424242, $phones[0]->phonenumber);
161
        self::assertSame($phones[0]->getUser(), $users[0]);
162
    }
163
164
    public function testJoinedOneToOneNativeQuery() : void
165
    {
166
        $user = new CmsUser();
167
168
        $user->name     = 'Roman';
169
        $user->username = 'romanb';
170
        $user->status   = 'dev';
171
172
        $addr = new CmsAddress();
173
174
        $addr->country = 'germany';
175
        $addr->zip     = 10827;
176
        $addr->city    = 'Berlin';
177
178
        $user->setAddress($addr);
179
180
        $this->em->persist($user);
181
        $this->em->flush();
182
        $this->em->clear();
183
184
        $rsm = new ResultSetMapping();
185
186
        $rsm->addEntityResult(CmsUser::class, 'u');
187
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
188
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name');
189
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status');
190
        $rsm->addJoinedEntityResult(CmsAddress::class, 'a', 'u', 'address');
191
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('a_id'), 'id');
192
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country');
193
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip');
194
        $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city');
195
196
        $query = $this->em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
197
198
        $query->setParameter(1, 'romanb');
199
200
        $users = $query->getResult();
201
202
        self::assertCount(1, $users);
203
        self::assertInstanceOf(CmsUser::class, $users[0]);
204
        self::assertEquals('Roman', $users[0]->name);
205
        self::assertInstanceOf(PersistentCollection::class, $users[0]->getPhonenumbers());
206
        self::assertFalse($users[0]->getPhonenumbers()->isInitialized());
207
        self::assertInstanceOf(CmsAddress::class, $users[0]->getAddress());
208
        self::assertEquals($users[0]->getAddress()->getUser(), $users[0]);
209
        self::assertEquals('germany', $users[0]->getAddress()->getCountry());
210
        self::assertEquals(10827, $users[0]->getAddress()->getZipCode());
211
        self::assertEquals('Berlin', $users[0]->getAddress()->getCity());
212
    }
213
214
    public function testFluentInterface() : void
215
    {
216
        $parameters = new ArrayCollection();
217
218
        $parameters->add(new Parameter(1, 'foo'));
219
        $parameters->add(new Parameter(2, 'bar'));
220
221
        $rsm = new ResultSetMapping();
222
223
        $q  = $this->em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm);
224
        $q2 = $q->setSQL('foo')
225
          ->setResultSetMapping($rsm)
226
          ->expireResultCache(true)
227
          ->setHint('foo', 'bar')
228
          ->setParameter(1, 'foo')
229
          ->setParameters($parameters)
230
          ->setResultCacheDriver(null)
231
          ->setResultCacheLifetime(3500);
232
233
        self::assertSame($q, $q2);
234
    }
235
236
    public function testJoinedOneToManyNativeQueryWithRSMBuilder() : void
237
    {
238
        $user = new CmsUser();
239
240
        $user->name     = 'Roman';
241
        $user->username = 'romanb';
242
        $user->status   = 'dev';
243
244
        $phone = new CmsPhonenumber();
245
246
        $phone->phonenumber = 424242;
247
248
        $user->addPhonenumber($phone);
249
250
        $this->em->persist($user);
251
        $this->em->flush();
252
        $this->em->clear();
253
254
        $rsm = new ResultSetMappingBuilder($this->em);
255
256
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
257
        $rsm->addJoinedEntityFromClassMetadata(CmsPhonenumber::class, 'p', 'u', 'phonenumbers');
258
        $query = $this->em->createNativeQuery('SELECT u.*, p.* FROM cms_users u LEFT JOIN cms_phonenumbers p ON u.id = p.user_id WHERE username = ?', $rsm);
259
260
        $query->setParameter(1, 'romanb');
261
262
        $users = $query->getResult();
263
264
        self::assertCount(1, $users);
265
        self::assertInstanceOf(CmsUser::class, $users[0]);
266
        self::assertEquals('Roman', $users[0]->name);
267
        self::assertInstanceOf(PersistentCollection::class, $users[0]->getPhonenumbers());
268
        self::assertTrue($users[0]->getPhonenumbers()->isInitialized());
269
        self::assertCount(1, $users[0]->getPhonenumbers());
270
271
        $phones = $users[0]->getPhonenumbers();
272
273
        self::assertEquals(424242, $phones[0]->phonenumber);
274
        self::assertSame($phones[0]->getUser(), $users[0]);
275
276
        $this->em->clear();
277
278
        $rsm = new ResultSetMappingBuilder($this->em);
279
280
        $rsm->addRootEntityFromClassMetadata(CmsPhonenumber::class, 'p');
281
282
        $query = $this->em->createNativeQuery('SELECT p.* FROM cms_phonenumbers p WHERE p.phonenumber = ?', $rsm);
283
284
        $query->setParameter(1, $phone->phonenumber);
285
286
        $phone = $query->getSingleResult();
287
288
        self::assertNotNull($phone->getUser());
289
        self::assertEquals($user->name, $phone->getUser()->getName());
290
    }
291
292
    public function testJoinedOneToOneNativeQueryWithRSMBuilder() : void
293
    {
294
        $user = new CmsUser();
295
296
        $user->name     = 'Roman';
297
        $user->username = 'romanb';
298
        $user->status   = 'dev';
299
300
        $addr = new CmsAddress();
301
302
        $addr->country = 'germany';
303
        $addr->zip     = 10827;
304
        $addr->city    = 'Berlin';
305
306
        $user->setAddress($addr);
307
308
        $this->em->persist($user);
309
        $this->em->flush();
310
        $this->em->clear();
311
312
        $rsm = new ResultSetMappingBuilder($this->em);
313
314
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
315
        $rsm->addJoinedEntityFromClassMetadata(CmsAddress::class, 'a', 'u', 'address', ['id' => 'a_id']);
316
317
        $query = $this->em->createNativeQuery('SELECT u.*, a.*, a.id AS a_id FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
318
319
        $query->setParameter(1, 'romanb');
320
321
        $users = $query->getResult();
322
323
        self::assertCount(1, $users);
324
        self::assertInstanceOf(CmsUser::class, $users[0]);
325
        self::assertEquals('Roman', $users[0]->name);
326
        self::assertInstanceOf(PersistentCollection::class, $users[0]->getPhonenumbers());
327
        self::assertFalse($users[0]->getPhonenumbers()->isInitialized());
328
        self::assertInstanceOf(CmsAddress::class, $users[0]->getAddress());
329
        self::assertEquals($users[0]->getAddress()->getUser(), $users[0]);
330
        self::assertEquals('germany', $users[0]->getAddress()->getCountry());
331
        self::assertEquals(10827, $users[0]->getAddress()->getZipCode());
332
        self::assertEquals('Berlin', $users[0]->getAddress()->getCity());
333
334
        $this->em->clear();
335
336
        $rsm = new ResultSetMappingBuilder($this->em);
337
338
        $rsm->addRootEntityFromClassMetadata(CmsAddress::class, 'a');
339
340
        $query = $this->em->createNativeQuery('SELECT a.* FROM cms_addresses a WHERE a.id = ?', $rsm);
341
342
        $query->setParameter(1, $addr->getId());
343
344
        $address = $query->getSingleResult();
345
346
        self::assertNotNull($address->getUser());
347
        self::assertEquals($user->name, $address->getUser()->getName());
348
    }
349
350
    /**
351
     * @group rsm-sti
352
     */
353
    public function testConcreteClassInSingleTableInheritanceSchemaWithRSMBuilderIsFine() : void
354
    {
355
        $rsm = new ResultSetMappingBuilder($this->em);
356
357
        $rsm->addRootEntityFromClassMetadata(CompanyFixContract::class, 'c');
358
359
        self::assertSame(CompanyFixContract::class, $rsm->getClassName('c'));
360
    }
361
362
    /**
363
     * @group rsm-sti
364
     */
365
    public function testAbstractClassInSingleTableInheritanceSchemaWithRSMBuilderThrowsException() : void
366
    {
367
        $this->expectException(InvalidArgumentException::class);
368
        $this->expectExceptionMessage('ResultSetMapping builder does not currently support your inheritance scheme.');
369
370
        $rsm = new ResultSetMappingBuilder($this->em);
371
372
        $rsm->addRootEntityFromClassMetadata(CompanyContract::class, 'c');
373
    }
374
375
    /**
376
     * @group rsm-sti
377
     */
378
    public function testConcreteClassInJoinedTableInheritanceSchemaWithRSMBuilderIsFine() : void
379
    {
380
        $rsm = new ResultSetMappingBuilder($this->em);
381
382
        $rsm->addRootEntityFromClassMetadata(CompanyAuction::class, 'c');
383
384
        self::assertSame(CompanyAuction::class, $rsm->getClassName('c'));
385
    }
386
387
    /**
388
     * @group rsm-sti
389
     */
390
    public function testAbstractClassInJoinedTableInheritanceSchemaWithRSMBuilderThrowsException() : void
391
    {
392
        $this->expectException(InvalidArgumentException::class);
393
        $this->expectExceptionMessage('ResultSetMapping builder does not currently support your inheritance scheme.');
394
395
        $rsm = new ResultSetMappingBuilder($this->em);
396
397
        $rsm->addRootEntityFromClassMetadata(CompanyEvent::class, 'c');
398
    }
399
400
    /**
401
     * @expectedException \InvalidArgumentException
402
     */
403
    public function testRSMBuilderThrowsExceptionOnColumnConflict() : void
404
    {
405
        $rsm = new ResultSetMappingBuilder($this->em);
406
407
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
408
        $rsm->addJoinedEntityFromClassMetadata(CmsAddress::class, 'a', 'u', 'address');
409
    }
410
411
    /**
412
     * @group PR-39
413
     */
414
    public function testUnknownParentAliasThrowsException() : void
415
    {
416
        $rsm = new ResultSetMappingBuilder($this->em);
417
418
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
419
        $rsm->addJoinedEntityFromClassMetadata(CmsAddress::class, 'a', 'un', 'address', ['id' => 'a_id']);
420
421
        $query = $this->em->createNativeQuery('SELECT u.*, a.*, a.id AS a_id FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
422
423
        $query->setParameter(1, 'romanb');
424
425
        $this->expectException(HydrationException::class);
426
        $this->expectExceptionMessage("The parent object of entity result with alias 'a' was not found. The parent alias is 'un'.");
427
428
        $query->getResult();
429
    }
430
431
    /**
432
     * @group DDC-2055
433
     */
434
    public function testGenerateSelectClauseNoRenameSingleEntity() : void
435
    {
436
        $rsm = new ResultSetMappingBuilder($this->em);
437
438
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
439
440
        $selectClause = $rsm->generateSelectClause();
441
442
        self::assertSQLEquals('u.id AS id, u.status AS status, u.username AS username, u.name AS name, u.email_id AS email_id', $selectClause);
443
    }
444
445
    /**
446
     * @group DDC-2055
447
     */
448
    public function testGenerateSelectClauseCustomRenames() : void
449
    {
450
        $rsm = new ResultSetMappingBuilder($this->em);
451
452
        $rsm->addRootEntityFromClassMetadata(
453
            CmsUser::class,
454
            'u',
455
            [
456
                'id' => 'id1',
457
                'username' => 'username2',
458
            ]
459
        );
460
461
        $selectClause = $rsm->generateSelectClause();
462
463
        self::assertSQLEquals('u.id AS id1, u.status AS status, u.username AS username2, u.name AS name, u.email_id AS email_id', $selectClause);
464
    }
465
466
    /**
467
     * @group DDC-2055
468
     */
469
    public function testGenerateSelectClauseRenameTableAlias() : void
470
    {
471
        $rsm = new ResultSetMappingBuilder($this->em);
472
473
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
474
475
        $selectClause = $rsm->generateSelectClause(['u' => 'u1']);
476
477
        self::assertSQLEquals('u1.id AS id, u1.status AS status, u1.username AS username, u1.name AS name, u1.email_id AS email_id', $selectClause);
478
    }
479
480
    /**
481
     * @group DDC-2055
482
     */
483
    public function testGenerateSelectClauseIncrement() : void
484
    {
485
        $rsm = new ResultSetMappingBuilder($this->em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
486
487
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
488
489
        $selectClause = $rsm->generateSelectClause();
490
491
        self::assertSQLEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', $selectClause);
492
    }
493
494
    /**
495
     * @group DDC-2055
496
     */
497
    public function testGenerateSelectClauseToString() : void
498
    {
499
        $rsm = new ResultSetMappingBuilder($this->em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
500
501
        $rsm->addRootEntityFromClassMetadata(CmsUser::class, 'u');
502
503
        self::assertSQLEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', (string) $rsm);
504
    }
505
506
    /**
507
     * @group DDC-3899
508
     */
509
    public function testGenerateSelectClauseWithDiscriminatorColumn() : void
510
    {
511
        $rsm = new ResultSetMappingBuilder($this->em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
512
513
        $rsm->addEntityResult(DDC3899User::class, 'u');
514
        $rsm->addJoinedEntityResult(DDC3899FixContract::class, 'c', 'u', 'contracts');
515
        $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
516
        $rsm->setDiscriminatorColumn('c', $this->platform->getSQLResultCasing('discr'));
517
518
        $selectClause = $rsm->generateSelectClause(['u' => 'u1', 'c' => 'c1']);
519
520
        self::assertSQLEquals('u1.id as id, c1.discr as discr', $selectClause);
521
    }
522
523
    protected function getResultSetMapping(AbstractQuery $query) : ResultSetMapping
524
    {
525
        $reflClass  = new ReflectionClass($query);
526
        $reflMethod = $reflClass->getMethod('getResultSetMapping');
527
528
        $reflMethod->setAccessible(true);
529
530
        return $reflMethod->invoke($query);
531
    }
532
}
533