Failed Conditions
Pull Request — master (#6743)
by Grégoire
18:17 queued 12:33
created

testCountComplexWithoutOutputWalker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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