Passed
Pull Request — master (#7222)
by
unknown
11:41
created

testCountQueryStripsParametersInSelect()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 0
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Functional;
6
7
use Doctrine\ORM\Query;
8
use Doctrine\ORM\Tools\Pagination\Paginator;
9
use Doctrine\Tests\Models\CMS\CmsArticle;
10
use Doctrine\Tests\Models\CMS\CmsEmail;
11
use Doctrine\Tests\Models\CMS\CmsGroup;
12
use Doctrine\Tests\Models\CMS\CmsUser;
13
use Doctrine\Tests\Models\Company\CompanyManager;
14
use Doctrine\Tests\Models\Pagination\Company;
15
use Doctrine\Tests\Models\Pagination\Department;
16
use Doctrine\Tests\Models\Pagination\Logo;
17
use Doctrine\Tests\Models\Pagination\User1;
18
use Doctrine\Tests\OrmFunctionalTestCase;
19
use ReflectionMethod;
20
use function count;
21
use function iterator_to_array;
22
use function sprintf;
23
24
/**
25
 * @group DDC-1613
26
 */
27
class PaginationTest extends OrmFunctionalTestCase
28
{
29
    protected function setUp() : void
30
    {
31
        $this->useModelSet('cms');
32
        $this->useModelSet('pagination');
33
        $this->useModelSet('company');
34
        parent::setUp();
35
        $this->populate();
36
    }
37
38
    /**
39
     * @dataProvider useOutputWalkers
40
     */
41
    public function testCountSimpleWithoutJoin($useOutputWalkers) : void
42
    {
43
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u';
44
        $query = $this->em->createQuery($dql);
45
46
        $paginator = new Paginator($query);
47
        $paginator->setUseOutputWalkers($useOutputWalkers);
48
        self::assertCount(9, $paginator);
49
    }
50
51
    /**
52
     * @dataProvider useOutputWalkers
53
     */
54
    public function testCountWithFetchJoin($useOutputWalkers) : void
55
    {
56
        $dql   = 'SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g';
57
        $query = $this->em->createQuery($dql);
58
59
        $paginator = new Paginator($query);
60
        $paginator->setUseOutputWalkers($useOutputWalkers);
61
        self::assertCount(9, $paginator);
62
    }
63
64
    public function testCountComplexWithOutputWalker() : void
65
    {
66
        $dql   = 'SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0';
67
        $query = $this->em->createQuery($dql);
68
69
        $paginator = new Paginator($query);
70
        $paginator->setUseOutputWalkers(true);
71
        self::assertCount(3, $paginator);
72
    }
73
74
    public function testCountComplexWithoutOutputWalker() : void
75
    {
76
        $dql   = 'SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0';
77
        $query = $this->em->createQuery($dql);
78
79
        $paginator = new Paginator($query);
80
        $paginator->setUseOutputWalkers(false);
81
82
        $this->expectException(\RuntimeException::class);
83
        $this->expectExceptionMessage('Cannot count query that uses a HAVING clause. Use the output walkers for pagination');
84
85
        self::assertCount(3, $paginator);
86
    }
87
88
    /**
89
     * @dataProvider useOutputWalkers
90
     */
91
    public function testCountWithComplexScalarOrderBy($useOutputWalkers) : void
92
    {
93
        $dql   = 'SELECT l FROM Doctrine\Tests\Models\Pagination\Logo l ORDER BY l.image_width * l.image_height DESC';
94
        $query = $this->em->createQuery($dql);
95
96
        $paginator = new Paginator($query);
97
        $paginator->setUseOutputWalkers($useOutputWalkers);
98
        self::assertCount(9, $paginator);
99
    }
100
101
    public function testPagesCount() : void
102
    {
103
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u';
104
        $query = $this->em->createQuery($dql);
105
106
        // Test without setMaxResults
107
        $paginator = new Paginator($query);
108
        self::assertNull($paginator->getPagesCount());
109
110
        // Test with setMaxResults
111
        $query->setMaxResults(4);
112
        $paginator = new Paginator($query);
113
        self::assertEquals(3, $paginator->getPagesCount());
114
115
        // Test with same total items and max results
116
        $query->setMaxResults(9);
117
        $paginator = new Paginator($query);
118
        self::assertEquals(1, $paginator->getPagesCount());
119
    }
120
121
    public function testPagesCountNoResult() : void
122
    {
123
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :name';
124
        $query = $this->em->createQuery($dql);
125
        $query->setParameter('name', 'unexistent');
126
127
        // Test without setMaxResults
128
        $paginator = new Paginator($query);
129
        self::assertNull($paginator->getPagesCount());
130
131
        // Test with setMaxResults
132
        $query->setMaxResults(4);
133
        $paginator = new Paginator($query);
134
        self::assertInternalType('int', $paginator->getPagesCount());
135
        self::assertEquals(0, $paginator->getPagesCount());
136
    }
137
138
    /**
139
     * @dataProvider useOutputWalkersAndFetchJoinCollection
140
     */
141
    public function testIterateSimpleWithoutJoin($useOutputWalkers, $fetchJoinCollection) : void
142
    {
143
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u';
144
        $query = $this->em->createQuery($dql);
145
146
        $paginator = new Paginator($query, $fetchJoinCollection);
147
        $paginator->setUseOutputWalkers($useOutputWalkers);
148
        self::assertCount(9, $paginator->getIterator());
149
150
        // Test with limit
151
        $query->setMaxResults(3);
152
        $paginator = new Paginator($query, $fetchJoinCollection);
153
        $paginator->setUseOutputWalkers($useOutputWalkers);
154
        self::assertCount(3, $paginator->getIterator());
155
156
        // Test with limit and offset
157
        $query->setMaxResults(3)->setFirstResult(4);
158
        $paginator = new Paginator($query, $fetchJoinCollection);
159
        $paginator->setUseOutputWalkers($useOutputWalkers);
160
        self::assertCount(3, $paginator->getIterator());
161
    }
162
163
    private function iterateWithOrderAsc($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
164
    {
165
        // Ascending
166
        $dql   = sprintf('%s ASC', $baseDql);
167
        $query = $this->em->createQuery($dql);
168
169
        $paginator = new Paginator($query, $fetchJoinCollection);
170
        $paginator->setUseOutputWalkers($useOutputWalkers);
171
        $iter = $paginator->getIterator();
172
        self::assertCount(9, $iter);
173
        $result = iterator_to_array($iter);
174
        self::assertEquals($checkField . '0', $result[0]->{$checkField});
175
    }
176
177
    private function iterateWithOrderAscWithLimit($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
178
    {
179
        // Ascending
180
        $dql   = sprintf('%s ASC', $baseDql);
181
        $query = $this->em->createQuery($dql);
182
183
        // With limit
184
        $query->setMaxResults(3);
185
        $paginator = new Paginator($query, $fetchJoinCollection);
186
        $paginator->setUseOutputWalkers($useOutputWalkers);
187
        $iter = $paginator->getIterator();
188
        self::assertCount(3, $iter);
189
        $result = iterator_to_array($iter);
190
        self::assertEquals($checkField . '0', $result[0]->{$checkField});
191
    }
192
193
    private function iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
194
    {
195
        // Ascending
196
        $dql   = sprintf('%s ASC', $baseDql);
197
        $query = $this->em->createQuery($dql);
198
199
        // With offset
200
        $query->setMaxResults(3)->setFirstResult(3);
201
        $paginator = new Paginator($query, $fetchJoinCollection);
202
        $paginator->setUseOutputWalkers($useOutputWalkers);
203
        $iter = $paginator->getIterator();
204
        self::assertCount(3, $iter);
205
        $result = iterator_to_array($iter);
206
        self::assertEquals($checkField . '3', $result[0]->{$checkField});
207
    }
208
209
    private function iterateWithOrderDesc($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
210
    {
211
        $dql   = sprintf('%s DESC', $baseDql);
212
        $query = $this->em->createQuery($dql);
213
214
        $paginator = new Paginator($query, $fetchJoinCollection);
215
        $paginator->setUseOutputWalkers($useOutputWalkers);
216
        $iter = $paginator->getIterator();
217
        self::assertCount(9, $iter);
218
        $result = iterator_to_array($iter);
219
        self::assertEquals($checkField . '8', $result[0]->{$checkField});
220
    }
221
222
    private function iterateWithOrderDescWithLimit($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
223
    {
224
        $dql   = sprintf('%s DESC', $baseDql);
225
        $query = $this->em->createQuery($dql);
226
227
        // With limit
228
        $query->setMaxResults(3);
229
        $paginator = new Paginator($query, $fetchJoinCollection);
230
        $paginator->setUseOutputWalkers($useOutputWalkers);
231
        $iter = $paginator->getIterator();
232
        self::assertCount(3, $iter);
233
        $result = iterator_to_array($iter);
234
        self::assertEquals($checkField . '8', $result[0]->{$checkField});
235
    }
236
237
    private function iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $baseDql, $checkField)
238
    {
239
        $dql   = sprintf('%s DESC', $baseDql);
240
        $query = $this->em->createQuery($dql);
241
242
        // With offset
243
        $query->setMaxResults(3)->setFirstResult(3);
244
        $paginator = new Paginator($query, $fetchJoinCollection);
245
        $paginator->setUseOutputWalkers($useOutputWalkers);
246
        $iter = $paginator->getIterator();
247
        self::assertCount(3, $iter);
248
        $result = iterator_to_array($iter);
249
        self::assertEquals($checkField . '5', $result[0]->{$checkField});
250
    }
251
252
    /**
253
     * @dataProvider useOutputWalkersAndFetchJoinCollection
254
     */
255
    public function testIterateSimpleWithoutJoinWithOrder($useOutputWalkers, $fetchJoinCollection) : void
256
    {
257
        // Ascending
258
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username';
259
        $this->iterateWithOrderAsc($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
260
        $this->iterateWithOrderDesc($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
261
    }
262
263
    /**
264
     * @dataProvider useOutputWalkersAndFetchJoinCollection
265
     */
266
    public function testIterateSimpleWithoutJoinWithOrderAndLimit($useOutputWalkers, $fetchJoinCollection) : void
267
    {
268
        // Ascending
269
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username';
270
        $this->iterateWithOrderAscWithLimit($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
271
        $this->iterateWithOrderDescWithLimit($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
272
    }
273
274
    /**
275
     * @dataProvider useOutputWalkersAndFetchJoinCollection
276
     */
277
    public function testIterateSimpleWithoutJoinWithOrderAndLimitAndOffset($useOutputWalkers, $fetchJoinCollection) : void
278
    {
279
        // Ascending
280
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username';
281
        $this->iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
282
        $this->iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
283
    }
284
285
    /**
286
     * @dataProvider fetchJoinCollection
287
     */
288
    public function testIterateSimpleWithOutputWalkerWithoutJoinWithComplexOrder($fetchJoinCollection) : void
289
    {
290
        // Ascending
291
        $dql = 'SELECT l FROM Doctrine\Tests\Models\Pagination\Logo l ORDER BY l.image_width * l.image_height';
292
        $this->iterateWithOrderAsc(true, $fetchJoinCollection, $dql, 'image');
293
        $this->iterateWithOrderDesc(true, $fetchJoinCollection, $dql, 'image');
294
    }
295
296
    /**
297
     * @dataProvider fetchJoinCollection
298
     */
299
    public function testIterateSimpleWithOutputWalkerWithoutJoinWithComplexOrderAndLimit($fetchJoinCollection) : void
300
    {
301
        // Ascending
302
        $dql = 'SELECT l FROM Doctrine\Tests\Models\Pagination\Logo l ORDER BY l.image_width * l.image_height';
303
        $this->iterateWithOrderAscWithLimit(true, $fetchJoinCollection, $dql, 'image');
304
        $this->iterateWithOrderDescWithLimit(true, $fetchJoinCollection, $dql, 'image');
305
    }
306
307
    /**
308
     * @dataProvider fetchJoinCollection
309
     */
310
    public function testIterateSimpleWithOutputWalkerWithoutJoinWithComplexOrderAndLimitAndOffset($fetchJoinCollection) : void
311
    {
312
        // Ascending
313
        $dql = 'SELECT l FROM Doctrine\Tests\Models\Pagination\Logo l ORDER BY l.image_width * l.image_height';
314
        $this->iterateWithOrderAscWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'image');
315
        $this->iterateWithOrderDescWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'image');
316
    }
317
318
    /**
319
     * @dataProvider useOutputWalkers
320
     */
321
    public function testIterateWithFetchJoin($useOutputWalkers) : void
322
    {
323
        $dql   = 'SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g';
324
        $query = $this->em->createQuery($dql);
325
326
        $paginator = new Paginator($query, true);
327
        $paginator->setUseOutputWalkers($useOutputWalkers);
328
        self::assertCount(9, $paginator->getIterator());
329
    }
330
331
    /**
332
     * @dataProvider useOutputWalkers
333
     */
334
    public function testIterateWithFetchJoinWithOrder($useOutputWalkers) : void
335
    {
336
        $dql = 'SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g ORDER BY u.username';
337
        $this->iterateWithOrderAsc($useOutputWalkers, true, $dql, 'username');
338
        $this->iterateWithOrderDesc($useOutputWalkers, true, $dql, 'username');
339
    }
340
341
    /**
342
     * @dataProvider useOutputWalkers
343
     */
344
    public function testIterateWithFetchJoinWithOrderAndLimit($useOutputWalkers) : void
345
    {
346
        $dql = 'SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g ORDER BY u.username';
347
        $this->iterateWithOrderAscWithLimit($useOutputWalkers, true, $dql, 'username');
348
        $this->iterateWithOrderDescWithLimit($useOutputWalkers, true, $dql, 'username');
349
    }
350
351
    /**
352
     * @dataProvider useOutputWalkers
353
     */
354
    public function testIterateWithFetchJoinWithOrderAndLimitAndOffset($useOutputWalkers) : void
355
    {
356
        $dql = 'SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g ORDER BY u.username';
357
        $this->iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, true, $dql, 'username');
358
        $this->iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, true, $dql, 'username');
359
    }
360
361
    /**
362
     * @dataProvider useOutputWalkersAndFetchJoinCollection
363
     */
364
    public function testIterateWithRegularJoinWithOrderByColumnFromJoined($useOutputWalkers, $fetchJoinCollection) : void
365
    {
366
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.email e ORDER BY e.email';
367
        $this->iterateWithOrderAsc($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
368
        $this->iterateWithOrderDesc($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
369
    }
370
371
    /**
372
     * @dataProvider useOutputWalkersAndFetchJoinCollection
373
     */
374
    public function testIterateWithRegularJoinWithOrderByColumnFromJoinedWithLimit($useOutputWalkers, $fetchJoinCollection) : void
375
    {
376
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.email e ORDER BY e.email';
377
        $this->iterateWithOrderAscWithLimit($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
378
        $this->iterateWithOrderDescWithLimit($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
379
    }
380
381
    /**
382
     * @dataProvider useOutputWalkersAndFetchJoinCollection
383
     */
384
    public function testIterateWithRegularJoinWithOrderByColumnFromJoinedWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection) : void
385
    {
386
        $dql = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.email e ORDER BY e.email';
387
        $this->iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
388
        $this->iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, $fetchJoinCollection, $dql, 'username');
389
    }
390
391
    /**
392
     * @dataProvider fetchJoinCollection
393
     */
394
    public function testIterateWithOutputWalkersWithRegularJoinWithComplexOrderByReferencingJoined($fetchJoinCollection) : void
395
    {
396
        // long function name is loooooooooooong
397
398
        $dql = 'SELECT c FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_height * l.image_width';
399
        $this->iterateWithOrderAsc(true, $fetchJoinCollection, $dql, 'name');
400
        $this->iterateWithOrderDesc(true, $fetchJoinCollection, $dql, 'name');
401
    }
402
403
    /**
404
     * @dataProvider fetchJoinCollection
405
     */
406
    public function testIterateWithOutputWalkersWithRegularJoinWithComplexOrderByReferencingJoinedWithLimit($fetchJoinCollection) : void
407
    {
408
        // long function name is loooooooooooong
409
410
        $dql = 'SELECT c FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_height * l.image_width';
411
        $this->iterateWithOrderAscWithLimit(true, $fetchJoinCollection, $dql, 'name');
412
        $this->iterateWithOrderDescWithLimit(true, $fetchJoinCollection, $dql, 'name');
413
    }
414
415
    /**
416
     * @dataProvider fetchJoinCollection
417
     */
418
    public function testIterateWithOutputWalkersWithRegularJoinWithComplexOrderByReferencingJoinedWithLimitAndOffset($fetchJoinCollection) : void
419
    {
420
        // long function name is loooooooooooong
421
422
        $dql = 'SELECT c FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_height * l.image_width';
423
        $this->iterateWithOrderAscWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'name');
424
        $this->iterateWithOrderDescWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'name');
425
    }
426
427
    /**
428
     * @dataProvider useOutputWalkers
429
     */
430
    public function testIterateWithFetchJoinWithOrderByColumnFromJoined($useOutputWalkers) : void
431
    {
432
        $dql = 'SELECT u,g,e FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g JOIN u.email e ORDER BY e.email';
433
        $this->iterateWithOrderAsc($useOutputWalkers, true, $dql, 'username');
434
        $this->iterateWithOrderDesc($useOutputWalkers, true, $dql, 'username');
435
    }
436
437
    /**
438
     * @dataProvider useOutputWalkers
439
     */
440
    public function testIterateWithFetchJoinWithOrderByColumnFromJoinedWithLimit($useOutputWalkers) : void
441
    {
442
        $dql = 'SELECT u,g,e FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g JOIN u.email e ORDER BY e.email';
443
        $this->iterateWithOrderAscWithLimit($useOutputWalkers, true, $dql, 'username');
444
        $this->iterateWithOrderDescWithLimit($useOutputWalkers, true, $dql, 'username');
445
    }
446
447
    /**
448
     * @dataProvider useOutputWalkers
449
     */
450
    public function testIterateWithFetchJoinWithOrderByColumnFromJoinedWithLimitAndOffset($useOutputWalkers) : void
451
    {
452
        $dql = 'SELECT u,g,e FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g JOIN u.email e ORDER BY e.email';
453
        $this->iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, true, $dql, 'username');
454
        $this->iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, true, $dql, 'username');
455
    }
456
457
    /**
458
     * @dataProvider fetchJoinCollection
459
     */
460
    public function testIterateWithOutputWalkersWithFetchJoinWithComplexOrderByReferencingJoined($fetchJoinCollection) : void
461
    {
462
        $dql = 'SELECT c,l FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_width * l.image_height';
463
        $this->iterateWithOrderAsc(true, $fetchJoinCollection, $dql, 'name');
464
        $this->iterateWithOrderDesc(true, $fetchJoinCollection, $dql, 'name');
465
    }
466
467
    /**
468
     * @dataProvider fetchJoinCollection
469
     */
470
    public function testIterateWithOutputWalkersWithFetchJoinWithComplexOrderByReferencingJoinedWithLimit($fetchJoinCollection) : void
471
    {
472
        $dql = 'SELECT c,l FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_width * l.image_height';
473
        $this->iterateWithOrderAscWithLimit(true, $fetchJoinCollection, $dql, 'name');
474
        $this->iterateWithOrderDescWithLimit(true, $fetchJoinCollection, $dql, 'name');
475
    }
476
477
    /**
478
     * @dataProvider fetchJoinCollection
479
     */
480
    public function testIterateWithOutputWalkersWithFetchJoinWithComplexOrderByReferencingJoinedWithLimitAndOffset($fetchJoinCollection) : void
481
    {
482
        $dql = 'SELECT c,l FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.logo l ORDER BY l.image_width * l.image_height';
483
        $this->iterateWithOrderAscWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'name');
484
        $this->iterateWithOrderDescWithLimitAndOffset(true, $fetchJoinCollection, $dql, 'name');
485
    }
486
487
    /**
488
     * @dataProvider fetchJoinCollection
489
     */
490
    public function testIterateWithOutputWalkersWithFetchJoinWithComplexOrderByReferencingJoinedWithLimitAndOffsetWithInheritanceType($fetchJoinCollection) : void
491
    {
492
        $dql = 'SELECT u FROM Doctrine\Tests\Models\Pagination\User u ORDER BY u.id';
493
        $this->iterateWithOrderAscWithLimit(true, $fetchJoinCollection, $dql, 'name');
494
        $this->iterateWithOrderDescWithLimit(true, $fetchJoinCollection, $dql, 'name');
495
    }
496
497
    public function testIterateComplexWithOutputWalker() : void
498
    {
499
        $dql   = 'SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0';
500
        $query = $this->em->createQuery($dql);
501
502
        $paginator = new Paginator($query);
503
        $paginator->setUseOutputWalkers(true);
504
        self::assertCount(3, $paginator->getIterator());
505
    }
506
507
    public function testJoinedClassTableInheritance() : void
508
    {
509
        $dql   = 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyManager c ORDER BY c.startDate';
510
        $query = $this->em->createQuery($dql);
511
512
        $paginator = new Paginator($query);
513
        self::assertCount(1, $paginator->getIterator());
514
    }
515
516
    /**
517
     * @dataProvider useOutputWalkers
518
     */
519
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromBoth($useOutputWalkers) : void
520
    {
521
        $dql     = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
522
        $dqlAsc  = $dql . ' ASC, d.name';
523
        $dqlDesc = $dql . ' DESC, d.name';
524
        $this->iterateWithOrderAsc($useOutputWalkers, true, $dqlAsc, 'name');
525
        $this->iterateWithOrderDesc($useOutputWalkers, true, $dqlDesc, 'name');
526
    }
527
528
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromBothWithLimitWithOutputWalker() : void
529
    {
530
        $dql     = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
531
        $dqlAsc  = $dql . ' ASC, d.name';
532
        $dqlDesc = $dql . ' DESC, d.name';
533
        $this->iterateWithOrderAscWithLimit(true, true, $dqlAsc, 'name');
534
        $this->iterateWithOrderDescWithLimit(true, true, $dqlDesc, 'name');
535
    }
536
537
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromBothWithLimitWithoutOutputWalker() : void
538
    {
539
        $this->expectException(\RuntimeException::class);
540
        $this->expectExceptionMessage('Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers.');
541
542
        $dql     = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
543
        $dqlAsc  = $dql . ' ASC, d.name';
544
        $dqlDesc = $dql . ' DESC, d.name';
545
        $this->iterateWithOrderAscWithLimit(false, true, $dqlAsc, 'name');
546
        $this->iterateWithOrderDescWithLimit(false, true, $dqlDesc, 'name');
547
    }
548
549
    /**
550
     * @dataProvider useOutputWalkers
551
     */
552
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromRoot($useOutputWalkers) : void
553
    {
554
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
555
        $this->iterateWithOrderAsc($useOutputWalkers, true, $dql, 'name');
556
        $this->iterateWithOrderDesc($useOutputWalkers, true, $dql, 'name');
557
    }
558
559
    /**
560
     * @dataProvider useOutputWalkers
561
     */
562
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromRootWithLimit($useOutputWalkers) : void
563
    {
564
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
565
        $this->iterateWithOrderAscWithLimit($useOutputWalkers, true, $dql, 'name');
566
        $this->iterateWithOrderDescWithLimit($useOutputWalkers, true, $dql, 'name');
567
    }
568
569
    /**
570
     * @dataProvider useOutputWalkers
571
     */
572
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromRootWithLimitAndOffset($useOutputWalkers) : void
573
    {
574
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY c.name';
575
        $this->iterateWithOrderAscWithLimitAndOffset($useOutputWalkers, true, $dql, 'name');
576
        $this->iterateWithOrderDescWithLimitAndOffset($useOutputWalkers, true, $dql, 'name');
577
    }
578
579
    /**
580
     * @dataProvider useOutputWalkers
581
     */
582
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromJoined($useOutputWalkers) : void
583
    {
584
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY d.name';
585
        $this->iterateWithOrderAsc($useOutputWalkers, true, $dql, 'name');
586
        $this->iterateWithOrderDesc($useOutputWalkers, true, $dql, 'name');
587
    }
588
589
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromJoinedWithLimitWithOutputWalker() : void
590
    {
591
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY d.name';
592
        $this->iterateWithOrderAscWithLimit(true, true, $dql, 'name');
593
        $this->iterateWithOrderDescWithLimit(true, true, $dql, 'name');
594
    }
595
596
    public function testIterateWithFetchJoinOneToManyWithOrderByColumnFromJoinedWithLimitWithoutOutputWalker() : void
597
    {
598
        $this->expectException(\RuntimeException::class);
599
        $this->expectExceptionMessage('Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers.');
600
601
        $dql = 'SELECT c, d FROM Doctrine\Tests\Models\Pagination\Company c JOIN c.departments d ORDER BY d.name';
602
603
        $this->iterateWithOrderAscWithLimit(false, true, $dql, 'name');
604
        $this->iterateWithOrderDescWithLimit(false, true, $dql, 'name');
605
    }
606
607
    public function testCountWithCountSubqueryInWhereClauseWithOutputWalker() : void
608
    {
609
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((SELECT COUNT(s.id) FROM Doctrine\Tests\Models\CMS\CmsUser s) = 9) ORDER BY u.id desc';
610
        $query = $this->em->createQuery($dql);
611
612
        $paginator = new Paginator($query, true);
613
        $paginator->setUseOutputWalkers(true);
614
        self::assertCount(9, $paginator);
615
    }
616
617
    public function testIterateWithCountSubqueryInWhereClause() : void
618
    {
619
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((SELECT COUNT(s.id) FROM Doctrine\Tests\Models\CMS\CmsUser s) = 9) ORDER BY u.id desc';
620
        $query = $this->em->createQuery($dql);
621
622
        $paginator = new Paginator($query, true);
623
        $paginator->setUseOutputWalkers(true);
624
625
        $users = iterator_to_array($paginator->getIterator());
626
        self::assertCount(9, $users);
627
        foreach ($users as $i => $user) {
628
            self::assertEquals('username' . (8 - $i), $user->username);
629
        }
630
    }
631
632
    public function testDetectOutputWalker() : void
633
    {
634
        // This query works using the output walkers but causes an exception using the TreeWalker
635
        $dql   = 'SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0';
636
        $query = $this->em->createQuery($dql);
637
638
        // If the Paginator detects the custom output walker it should fall back to using the
639
        // Tree walkers for pagination, which leads to an exception. If the query works, the output walkers were used
640
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, Query\SqlWalker::class);
641
        $paginator = new Paginator($query);
642
643
        $this->expectException(\RuntimeException::class);
644
        $this->expectExceptionMessage('Cannot count query that uses a HAVING clause. Use the output walkers for pagination');
645
646
        count($paginator);
647
    }
648
649
    /**
650
     * Test using a paginator when the entity attribute name and corresponding column name are not the same.
651
     */
652
    public function testPaginationWithColumnAttributeNameDifference() : void
653
    {
654
        $dql   = 'SELECT c FROM Doctrine\Tests\Models\Pagination\Company c ORDER BY c.id';
655
        $query = $this->em->createQuery($dql);
656
657
        $paginator = new Paginator($query);
658
        $paginator->getIterator();
659
660
        self::assertCount(9, $paginator->getIterator());
661
    }
662
663
    public function testCloneQuery() : void
664
    {
665
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u';
666
        $query = $this->em->createQuery($dql);
667
668
        $paginator = new Paginator($query);
669
        $paginator->getIterator();
670
671
        self::assertTrue($query->getParameters()->isEmpty());
672
    }
673
674
    public function testQueryWalkerIsKept() : void
675
    {
676
        $dql   = 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u';
677
        $query = $this->em->createQuery($dql);
678
        $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, [CustomPaginationTestTreeWalker::class]);
679
680
        $paginator = new Paginator($query, true);
681
        $paginator->setUseOutputWalkers(false);
682
        self::assertCount(1, $paginator->getIterator());
683
        self::assertEquals(1, $paginator->count());
684
    }
685
686
    public function testCountQueryStripsParametersInSelect() : void
687
    {
688
        $query = $this->em->createQuery(
689
            'SELECT u, (CASE WHEN u.id < :vipMaxId THEN 1 ELSE 0 END) AS hidden promotedFirst
690
            FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u
691
            WHERE u.id < :id or 1=1'
692
        );
693
        $query->setParameter('vipMaxId', 10);
694
        $query->setParameter('id', 100);
695
        $query->setFirstResult(null)->setMaxResults(null);
696
697
        $paginator = new Paginator($query);
698
699
        $getCountQuery = new ReflectionMethod($paginator, 'getCountQuery');
700
701
        $getCountQuery->setAccessible(true);
702
703
        self::assertCount(2, $getCountQuery->invoke($paginator)->getParameters());
704
        self::assertCount(9, $paginator);
705
706
        $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, Query\SqlWalker::class);
707
708
        $paginator = new Paginator($query);
709
710
        // if select part of query is replaced with count(...) paginator should remove
711
        // parameters from query object not used in new query.
712
        self::assertCount(1, $getCountQuery->invoke($paginator)->getParameters());
713
        self::assertCount(9, $paginator);
714
    }
715
716
    /**
717
     * @dataProvider useOutputWalkersAndFetchJoinCollection
718
     */
719
    public function testPaginationWithSubSelectOrderByExpression($useOutputWalker, $fetchJoinCollection) : void
720
    {
721
        $query = $this->em->createQuery(
722
            'SELECT u, 
723
                (
724
                    SELECT MAX(a.version)
725
                    FROM Doctrine\\Tests\\Models\\CMS\\CmsArticle a
726
                    WHERE a.user = u
727
                ) AS HIDDEN max_version
728
            FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u
729
            ORDER BY max_version DESC'
730
        );
731
732
        $paginator = new Paginator($query, $fetchJoinCollection);
733
        $paginator->setUseOutputWalkers($useOutputWalker);
734
735
        self::assertCount(9, $paginator->getIterator());
736
    }
737
738
    public function populate()
739
    {
740
        $groups = [];
741
        for ($j = 0; $j < 3; $j++) {
742
            $group       = new CmsGroup();
743
            $group->name = sprintf('group%d', $j);
744
            $groups[]    = $group;
745
            $this->em->persist($group);
746
        }
747
748
        for ($i = 0; $i < 9; $i++) {
749
            $user               = new CmsUser();
750
            $user->name         = sprintf('Name%d', $i);
751
            $user->username     = sprintf('username%d', $i);
752
            $user->status       = 'active';
753
            $user->email        = new CmsEmail();
754
            $user->email->user  = $user;
755
            $user->email->email = sprintf('email%d', $i);
756
            for ($j = 0; $j < 3; $j++) {
757
                $user->addGroup($groups[$j]);
758
            }
759
            $this->em->persist($user);
760
            for ($j = 0; $j < $i + 1; $j++) {
761
                $article        = new CmsArticle();
762
                $article->topic = sprintf('topic%d%d', $i, $j);
763
                $article->text  = sprintf('text%d%d', $i, $j);
764
                $article->setAuthor($user);
765
                $article->version = 0;
766
                $this->em->persist($article);
767
            }
768
        }
769
770
        for ($i = 0; $i < 9; $i++) {
771
            $company                     = new Company();
772
            $company->name               = sprintf('name%d', $i);
773
            $company->logo               = new Logo();
774
            $company->logo->image        = sprintf('image%d', $i);
775
            $company->logo->image_width  = 100 + $i;
776
            $company->logo->image_height = 100 + $i;
777
            $company->logo->company      = $company;
778
            for ($j=0; $j<3; $j++) {
779
                $department             = new Department();
780
                $department->name       = sprintf('name%d%d', $i, $j);
781
                $department->company    = $company;
782
                $company->departments[] = $department;
783
            }
784
            $this->em->persist($company);
785
        }
786
787
        for ($i = 0; $i < 9; $i++) {
788
            $user        = new User1();
789
            $user->name  = sprintf('name%d', $i);
790
            $user->email = sprintf('email%d', $i);
791
            $this->em->persist($user);
792
        }
793
794
        $manager = new CompanyManager();
795
        $manager->setName('Roman B.');
796
        $manager->setTitle('Foo');
797
        $manager->setDepartment('IT');
798
        $manager->setSalary(100000);
799
800
        $this->em->persist($manager);
801
802
        $this->em->flush();
803
    }
804
805
    public function useOutputWalkers()
806
    {
807
        return [
808
            [true],
809
            [false],
810
        ];
811
    }
812
813
    public function fetchJoinCollection()
814
    {
815
        return [
816
            [true],
817
            [false],
818
        ];
819
    }
820
821
    public function useOutputWalkersAndFetchJoinCollection()
822
    {
823
        return [
824
            [true, false],
825
            [true, true],
826
            [false, false],
827
            [false, true],
828
        ];
829
    }
830
}
831
832
class CustomPaginationTestTreeWalker extends Query\TreeWalkerAdapter
833
{
834
    public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
835
    {
836
        $condition = new Query\AST\ConditionalPrimary();
837
838
        $path       = new Query\AST\PathExpression(Query\AST\PathExpression::TYPE_STATE_FIELD, 'u', 'name');
839
        $path->type = Query\AST\PathExpression::TYPE_STATE_FIELD;
840
841
        $condition->simpleConditionalExpression = new Query\AST\ComparisonExpression(
842
            $path,
843
            '=',
844
            new Query\AST\Literal(Query\AST\Literal::STRING, 'Name1')
845
        );
846
847
        $selectStatement->whereClause = new Query\AST\WhereClause($condition);
0 ignored issues
show
Bug introduced by
$condition of type Doctrine\ORM\Query\AST\ConditionalPrimary is incompatible with the type Doctrine\ORM\Query\AST\ConditionalExpression expected by parameter $conditionalExpression of Doctrine\ORM\Query\AST\WhereClause::__construct(). ( Ignorable by Annotation )

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

847
        $selectStatement->whereClause = new Query\AST\WhereClause(/** @scrutinizer ignore-type */ $condition);
Loading history...
848
    }
849
}
850