[TASK] Remove ext:dbal from installation steps
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Database / Query / QueryBuilderTest.php
1 <?php
2 declare (strict_types = 1);
3 namespace TYPO3\CMS\Core\Tests\Unit\Database\Query;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Prophecy\Argument;
19 use TYPO3\CMS\Core\Database\Connection;
20 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
21 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
22 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
23 use TYPO3\CMS\Core\Tests\Unit\Database\Mocks\MockPlatform;
24 use TYPO3\CMS\Core\Tests\UnitTestCase;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 class QueryBuilderTest extends UnitTestCase
28 {
29 /**
30 * @var Connection|\Prophecy\Prophecy\ObjectProphecy
31 */
32 protected $connection;
33
34 /**
35 * @var \Doctrine\DBAL\Platforms\AbstractPlatform
36 */
37 protected $platform;
38
39 /**
40 * @var QueryBuilder
41 */
42 protected $subject;
43
44 /**
45 * @var \Doctrine\DBAL\Query\QueryBuilder|\Prophecy\Prophecy\ObjectProphecy
46 */
47 protected $concreteQueryBuilder;
48
49 /**
50 * Create a new database connection mock object for every test.
51 *
52 * @return void
53 */
54 protected function setUp()
55 {
56 parent::setUp();
57
58 $this->concreteQueryBuilder = $this->prophesize(\Doctrine\DBAL\Query\QueryBuilder::class);
59
60 $this->connection = $this->prophesize(Connection::class);
61 $this->connection->getDatabasePlatform()->willReturn(new MockPlatform());
62
63 $this->subject = GeneralUtility::makeInstance(
64 QueryBuilder::class,
65 $this->connection->reveal(),
66 null,
67 $this->concreteQueryBuilder->reveal()
68 );
69 }
70
71 /**
72 * @test
73 */
74 public function exprReturnsExpressionBuilderForConnection()
75 {
76 $this->connection->getExpressionBuilder()
77 ->shouldBeCalled()
78 ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
79
80 $this->subject->expr();
81 }
82
83 /**
84 * @test
85 */
86 public function getTypeDelegatesToConcreteQueryBuilder()
87 {
88 $this->concreteQueryBuilder->getType()
89 ->shouldBeCalled()
90 ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT);
91
92 $this->subject->getType();
93 }
94
95 /**
96 * @test
97 */
98 public function getStateDelegatesToConcreteQueryBuilder()
99 {
100 $this->concreteQueryBuilder->getState()
101 ->shouldBeCalled()
102 ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::STATE_CLEAN);
103
104 $this->subject->getState();
105 }
106
107 /**
108 * @test
109 */
110 public function getSQLDelegatesToConcreteQueryBuilder()
111 {
112 $this->concreteQueryBuilder->getSQL()
113 ->shouldBeCalled()
114 ->willReturn('UPDATE aTable SET pid = 7');
115 $this->concreteQueryBuilder->getType()
116 ->willReturn(2); // Update Type
117
118 $this->subject->getSQL();
119 }
120
121 /**
122 * @test
123 */
124 public function setParameterDelegatesToConcreteQueryBuilder()
125 {
126 $this->concreteQueryBuilder->setParameter(Argument::exact('aField'), Argument::exact(5), Argument::cetera())
127 ->shouldBeCalled()
128 ->willReturn($this->subject);
129
130 $this->subject->setParameter('aField', 5);
131 }
132
133 /**
134 * @test
135 */
136 public function setParametersDelegatesToConcreteQueryBuilder()
137 {
138 $this->concreteQueryBuilder->setParameters(Argument::exact(['aField' => 'aValue']), Argument::exact([]))
139 ->shouldBeCalled()
140 ->willReturn($this->subject);
141
142 $this->subject->setParameters(['aField' => 'aValue']);
143 }
144
145 /**
146 * @test
147 */
148 public function getParametersDelegatesToConcreteQueryBuilder()
149 {
150 $this->concreteQueryBuilder->getParameters()
151 ->shouldBeCalled()
152 ->willReturn(['aField' => 'aValue']);
153
154 $this->subject->getParameters();
155 }
156
157 /**
158 * @test
159 */
160 public function getParameterDelegatesToConcreteQueryBuilder()
161 {
162 $this->concreteQueryBuilder->getParameter(Argument::exact('aField'))
163 ->shouldBeCalled()
164 ->willReturn('aValue');
165
166 $this->subject->getParameter('aField');
167 }
168
169 /**
170 * @test
171 */
172 public function getParameterTypesDelegatesToConcreteQueryBuilder()
173 {
174 $this->concreteQueryBuilder->getParameterTypes()
175 ->shouldBeCalled()
176 ->willReturn([]);
177
178 $this->subject->getParameterTypes();
179 }
180
181 /**
182 * @test
183 */
184 public function getParameterTypeDelegatesToConcreteQueryBuilder()
185 {
186 $this->concreteQueryBuilder->getParameterType(Argument::exact('aField'))
187 ->shouldBeCalled()
188 ->willReturn(Connection::PARAM_STR);
189
190 $this->subject->getParameterType('aField');
191 }
192
193 /**
194 * @test
195 */
196 public function setFirstResultDelegatesToConcreteQueryBuilder()
197 {
198 $this->concreteQueryBuilder->setFirstResult(Argument::cetera())
199 ->shouldBeCalled()
200 ->willReturn($this->subject);
201
202 $this->subject->setFirstResult(1);
203 }
204
205 /**
206 * @test
207 */
208 public function getFirstResultDelegatesToConcreteQueryBuilder()
209 {
210 $this->concreteQueryBuilder->getFirstResult()
211 ->shouldBeCalled()
212 ->willReturn(1);
213
214 $this->subject->getFirstResult();
215 }
216
217 /**
218 * @test
219 */
220 public function setMaxResultsDelegatesToConcreteQueryBuilder()
221 {
222 $this->concreteQueryBuilder->setMaxResults(Argument::cetera())
223 ->shouldBeCalled()
224 ->willReturn($this->subject);
225
226 $this->subject->setMaxResults(1);
227 }
228
229 /**
230 * @test
231 */
232 public function getMaxResultsDelegatesToConcreteQueryBuilder()
233 {
234 $this->concreteQueryBuilder->getMaxResults()
235 ->shouldBeCalled()
236 ->willReturn(1);
237
238 $this->subject->getMaxResults();
239 }
240
241 /**
242 * @test
243 */
244 public function addDelegatesToConcreteQueryBuilder()
245 {
246 $this->concreteQueryBuilder->add(Argument::exact('select'), Argument::exact('aField'), Argument::cetera())
247 ->shouldBeCalled()
248 ->willReturn($this->subject);
249
250 $this->subject->add('select', 'aField');
251 }
252
253 /**
254 * @test
255 */
256 public function countBuildsExpressionAndCallsSelect()
257 {
258 $this->concreteQueryBuilder->select(Argument::exact('COUNT(*)'))
259 ->shouldBeCalled()
260 ->willReturn($this->subject);
261
262 $this->subject->count('*');
263 }
264
265 /**
266 * @test
267 */
268 public function selectQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
269 {
270 $this->connection->quoteIdentifier('aField')
271 ->shouldBeCalled()
272 ->willReturnArgument(0);
273 $this->connection->quoteIdentifier('anotherField')
274 ->shouldBeCalled()
275 ->willReturnArgument(0);
276 $this->concreteQueryBuilder->select(Argument::exact('aField'), Argument::exact('anotherField'))
277 ->shouldBeCalled()
278 ->willReturn($this->subject);
279
280 $this->subject->select('aField', 'anotherField');
281 }
282
283 public function quoteIdentifiersForSelectDataProvider()
284 {
285 return [
286 'fieldName' => [
287 'fieldName',
288 '"fieldName"',
289 ],
290 'tableName.fieldName' => [
291 'tableName.fieldName',
292 '"tableName"."fieldName"',
293 ],
294 'tableName.*' => [
295 'tableName.*',
296 '"tableName".*',
297 ],
298 '*' => [
299 '*',
300 '*',
301 ],
302 'fieldName AS anotherFieldName' => [
303 'fieldName AS anotherFieldName',
304 '"fieldName" AS "anotherFieldName"',
305 ],
306 'tableName.fieldName AS anotherFieldName' => [
307 'tableName.fieldName AS anotherFieldName',
308 '"tableName"."fieldName" AS "anotherFieldName"',
309 ],
310 'tableName.fieldName AS anotherTable.anotherFieldName' => [
311 'tableName.fieldName AS anotherTable.anotherFieldName',
312 '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"',
313 ],
314 ];
315 }
316
317 /**
318 * @test
319 * @dataProvider quoteIdentifiersForSelectDataProvider
320 * @param string $identifier
321 * @param string $expectedResult
322 */
323 public function quoteIdentifiersForSelect($identifier, $expectedResult)
324 {
325 $this->connection->quoteIdentifier(Argument::cetera())->will(
326 function ($args) {
327 $platform = new MockPlatform();
328
329 return $platform->quoteIdentifier($args[0]);
330 }
331 );
332
333 $this->assertSame([$expectedResult], $this->subject->quoteIdentifiersForSelect([$identifier]));
334 }
335
336 /**
337 * @test
338 */
339 public function quoteIdentifiersForSelectWithInvalidAlias()
340 {
341 $this->expectException(\InvalidArgumentException::class);
342 $this->expectExceptionCode(1461170686);
343
344 $this->connection->quoteIdentifier(Argument::cetera())->will(
345 function ($args) {
346 $platform = new MockPlatform();
347
348 return $platform->quoteIdentifier($args[0]);
349 }
350 );
351 $this->subject->quoteIdentifiersForSelect(['aField AS anotherField,someField AS someThing']);
352 }
353
354 /**
355 * @test
356 */
357 public function selectDoesNotQuoteStarPlaceholder()
358 {
359 $this->connection->quoteIdentifier('aField')
360 ->shouldBeCalled()
361 ->willReturnArgument(0);
362 $this->connection->quoteIdentifier('*')
363 ->shouldNotBeCalled();
364 $this->concreteQueryBuilder->select(Argument::exact('aField'), Argument::exact('*'))
365 ->shouldBeCalled()
366 ->willReturn($this->subject);
367
368 $this->subject->select('aField', '*');
369 }
370
371 /**
372 * @test
373 */
374 public function addSelectQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
375 {
376 $this->connection->quoteIdentifier('aField')
377 ->shouldBeCalled()
378 ->willReturnArgument(0);
379 $this->connection->quoteIdentifier('anotherField')
380 ->shouldBeCalled()
381 ->willReturnArgument(0);
382 $this->concreteQueryBuilder->addSelect(Argument::exact('aField'), Argument::exact('anotherField'))
383 ->shouldBeCalled()
384 ->willReturn($this->subject);
385
386 $this->subject->addSelect('aField', 'anotherField');
387 }
388
389 /**
390 * @test
391 */
392 public function addSelectDoesNotQuoteStarPlaceholder()
393 {
394 $this->connection->quoteIdentifier('aField')
395 ->shouldBeCalled()
396 ->willReturnArgument(0);
397 $this->connection->quoteIdentifier('*')
398 ->shouldNotBeCalled();
399 $this->concreteQueryBuilder->addSelect(Argument::exact('aField'), Argument::exact('*'))
400 ->shouldBeCalled()
401 ->willReturn($this->subject);
402
403 $this->subject->addSelect('aField', '*');
404 }
405
406 /**
407 * @test
408 */
409 public function selectLiteralDirectlyDelegatesToConcreteQueryBuilder()
410 {
411 $this->connection->quoteIdentifier(Argument::cetera())
412 ->shouldNotBeCalled();
413 $this->concreteQueryBuilder->select(Argument::exact('MAX(aField) AS anAlias'))
414 ->shouldBeCalled()
415 ->willReturn($this->subject);
416
417 $this->subject->selectLiteral('MAX(aField) AS anAlias');
418 }
419
420 /**
421 * @test
422 */
423 public function addSelectLiteralDirectlyDelegatesToConcreteQueryBuilder()
424 {
425 $this->connection->quoteIdentifier(Argument::cetera())
426 ->shouldNotBeCalled();
427 $this->concreteQueryBuilder->addSelect(Argument::exact('MAX(aField) AS anAlias'))
428 ->shouldBeCalled()
429 ->willReturn($this->subject);
430
431 $this->subject->addSelectLiteral('MAX(aField) AS anAlias');
432 }
433
434 /**
435 * @test
436 * @todo: Test with alias
437 */
438 public function deleteQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
439 {
440 $this->connection->quoteIdentifier('aTable')
441 ->shouldBeCalled()
442 ->willReturnArgument(0);
443 $this->concreteQueryBuilder->delete(Argument::exact('aTable'), Argument::cetera())
444 ->shouldBeCalled()
445 ->willReturn($this->subject);
446
447 $this->subject->delete('aTable');
448 }
449
450 /**
451 * @test
452 * @todo: Test with alias
453 */
454 public function updateQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
455 {
456 $this->connection->quoteIdentifier('aTable')
457 ->shouldBeCalled()
458 ->willReturnArgument(0);
459 $this->concreteQueryBuilder->update(Argument::exact('aTable'), Argument::cetera())
460 ->shouldBeCalled()
461 ->willReturn($this->subject);
462
463 $this->subject->update('aTable');
464 }
465
466 /**
467 * @test
468 */
469 public function insertQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
470 {
471 $this->connection->quoteIdentifier('aTable')
472 ->shouldBeCalled()
473 ->willReturnArgument(0);
474 $this->concreteQueryBuilder->insert(Argument::exact('aTable'))
475 ->shouldBeCalled()
476 ->willReturn($this->subject);
477
478 $this->subject->insert('aTable');
479 }
480
481 /**
482 * @test
483 * @todo: Test with alias
484 */
485 public function fromQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
486 {
487 $this->connection->quoteIdentifier('aTable')
488 ->shouldBeCalled()
489 ->willReturnArgument(0);
490 $this->concreteQueryBuilder->from(Argument::exact('aTable'), Argument::cetera())
491 ->shouldBeCalled()
492 ->willReturn($this->subject);
493
494 $this->subject->from('aTable');
495 }
496
497 /**
498 * @test
499 */
500 public function joinQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
501 {
502 $this->connection->quoteIdentifier('fromAlias')
503 ->shouldBeCalled()
504 ->willReturnArgument(0);
505 $this->connection->quoteIdentifier('join')
506 ->shouldBeCalled()
507 ->willReturnArgument(0);
508 $this->connection->quoteIdentifier('alias')
509 ->shouldBeCalled()
510 ->willReturnArgument(0);
511 $this->concreteQueryBuilder->innerJoin('fromAlias', 'join', 'alias', null)
512 ->shouldBeCalled()
513 ->willReturn($this->subject);
514
515 $this->subject->join('fromAlias', 'join', 'alias');
516 }
517
518 /**
519 * @test
520 */
521 public function innerJoinQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
522 {
523 $this->connection->quoteIdentifier('fromAlias')
524 ->shouldBeCalled()
525 ->willReturnArgument(0);
526 $this->connection->quoteIdentifier('join')
527 ->shouldBeCalled()
528 ->willReturnArgument(0);
529 $this->connection->quoteIdentifier('alias')
530 ->shouldBeCalled()
531 ->willReturnArgument(0);
532 $this->concreteQueryBuilder->innerJoin('fromAlias', 'join', 'alias', null)
533 ->shouldBeCalled()
534 ->willReturn($this->subject);
535
536 $this->subject->innerJoin('fromAlias', 'join', 'alias');
537 }
538
539 /**
540 * @test
541 */
542 public function leftJoinQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
543 {
544 $this->connection->quoteIdentifier('fromAlias')
545 ->shouldBeCalled()
546 ->willReturnArgument(0);
547 $this->connection->quoteIdentifier('join')
548 ->shouldBeCalled()
549 ->willReturnArgument(0);
550 $this->connection->quoteIdentifier('alias')
551 ->shouldBeCalled()
552 ->willReturnArgument(0);
553 $this->concreteQueryBuilder->leftJoin('fromAlias', 'join', 'alias', null)
554 ->shouldBeCalled()
555 ->willReturn($this->subject);
556
557 $this->subject->leftJoin('fromAlias', 'join', 'alias');
558 }
559
560 /**
561 * @test
562 */
563 public function rightJoinQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
564 {
565 $this->connection->quoteIdentifier('fromAlias')
566 ->shouldBeCalled()
567 ->willReturnArgument(0);
568 $this->connection->quoteIdentifier('join')
569 ->shouldBeCalled()
570 ->willReturnArgument(0);
571 $this->connection->quoteIdentifier('alias')
572 ->shouldBeCalled()
573 ->willReturnArgument(0);
574 $this->concreteQueryBuilder->rightJoin('fromAlias', 'join', 'alias', null)
575 ->shouldBeCalled()
576 ->willReturn($this->subject);
577
578 $this->subject->rightJoin('fromAlias', 'join', 'alias');
579 }
580
581 /**
582 * @test
583 */
584 public function setQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
585 {
586 $this->connection->quoteIdentifier('aField')
587 ->shouldBeCalled()
588 ->willReturnArgument(0);
589 $this->concreteQueryBuilder->createNamedParameter('aValue', Argument::cetera())
590 ->shouldBeCalled()
591 ->willReturn(':dcValue1');
592 $this->concreteQueryBuilder->set('aField', ':dcValue1')
593 ->shouldBeCalled()
594 ->willReturn($this->subject);
595
596 $this->subject->set('aField', 'aValue');
597 }
598
599 /**
600 * @test
601 */
602 public function setWithoutNamedParameterQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
603 {
604 $this->connection->quoteIdentifier('aField')
605 ->shouldBeCalled()
606 ->willReturnArgument(0);
607 $this->concreteQueryBuilder->createNamedParameter(Argument::cetera())->shouldNotBeCalled();
608 $this->concreteQueryBuilder->set('aField', 'aValue')
609 ->shouldBeCalled()
610 ->willReturn($this->subject);
611
612 $this->subject->set('aField', 'aValue', false);
613 }
614
615 /**
616 * @test
617 */
618 public function whereDelegatesToConcreteQueryBuilder()
619 {
620 $this->concreteQueryBuilder->where('uid=1', 'type=9')
621 ->shouldBeCalled()
622 ->willReturn($this->subject);
623
624 $this->subject->where('uid=1', 'type=9');
625 }
626
627 /**
628 * @test
629 */
630 public function andWhereDelegatesToConcreteQueryBuilder()
631 {
632 $this->concreteQueryBuilder->andWhere('uid=1', 'type=9')
633 ->shouldBeCalled()
634 ->willReturn($this->subject);
635
636 $this->subject->andWhere('uid=1', 'type=9');
637 }
638
639 /**
640 * @test
641 */
642 public function orWhereDelegatesToConcreteQueryBuilder()
643 {
644 $this->concreteQueryBuilder->orWhere('uid=1', 'type=9')
645 ->shouldBeCalled()
646 ->willReturn($this->subject);
647
648 $this->subject->orWhere('uid=1', 'type=9');
649 }
650
651 /**
652 * @test
653 */
654 public function groupByQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
655 {
656 $this->connection->quoteIdentifiers(['aField', 'anotherField'])
657 ->shouldBeCalled()
658 ->willReturnArgument(0);
659 $this->concreteQueryBuilder->groupBy('aField', 'anotherField')
660 ->shouldBeCalled()
661 ->willReturn($this->subject);
662
663 $this->subject->groupBy('aField', 'anotherField');
664 }
665
666 /**
667 * @test
668 */
669 public function addGroupByQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
670 {
671 $this->connection->quoteIdentifiers(['aField', 'anotherField'])
672 ->shouldBeCalled()
673 ->willReturnArgument(0);
674 $this->concreteQueryBuilder->addGroupBy('aField', 'anotherField')
675 ->shouldBeCalled()
676 ->willReturn($this->subject);
677
678 $this->subject->addGroupBy('aField', 'anotherField');
679 }
680
681 /**
682 * @test
683 */
684 public function setValueQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
685 {
686 $this->connection->quoteIdentifier('aField')
687 ->shouldBeCalled()
688 ->willReturnArgument(0);
689 $this->concreteQueryBuilder->createNamedParameter('aValue', Argument::cetera())
690 ->shouldBeCalled()
691 ->willReturn(':dcValue1');
692 $this->concreteQueryBuilder->setValue('aField', ':dcValue1')
693 ->shouldBeCalled()
694 ->willReturn($this->subject);
695
696 $this->subject->setValue('aField', 'aValue');
697 }
698
699 /**
700 * @test
701 */
702 public function setValueWithoudNamedParameterQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
703 {
704 $this->connection->quoteIdentifier('aField')
705 ->shouldBeCalled()
706 ->willReturnArgument(0);
707 $this->concreteQueryBuilder->setValue('aField', 'aValue')
708 ->shouldBeCalled()
709 ->willReturn($this->subject);
710
711 $this->subject->setValue('aField', 'aValue', false);
712 }
713
714 /**
715 * @test
716 */
717 public function valuesQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
718 {
719 $this->connection->quoteColumnValuePairs(['aField' => ':dcValue1', 'aValue' => ':dcValue2'])
720 ->shouldBeCalled()
721 ->willReturnArgument(0);
722 $this->concreteQueryBuilder->createNamedParameter(1, Argument::cetera())
723 ->shouldBeCalled()
724 ->willReturn(':dcValue1');
725 $this->concreteQueryBuilder->createNamedParameter(2, Argument::cetera())
726 ->shouldBeCalled()
727 ->willReturn(':dcValue2');
728 $this->concreteQueryBuilder->values(['aField' => ':dcValue1', 'aValue' => ':dcValue2'])
729 ->shouldBeCalled()
730 ->willReturn($this->subject);
731
732 $this->subject->values(['aField' => 1, 'aValue' => 2]);
733 }
734
735 /**
736 * @test
737 */
738 public function valuesWithoutNamedParametersQuotesIdentifiersAndDelegatesToConcreteQueryBuilder()
739 {
740 $this->connection->quoteColumnValuePairs(['aField' => 1, 'aValue' => 2])
741 ->shouldBeCalled()
742 ->willReturnArgument(0);
743 $this->concreteQueryBuilder->values(['aField' => 1, 'aValue' => 2])
744 ->shouldBeCalled()
745 ->willReturn($this->subject);
746
747 $this->subject->values(['aField' => 1, 'aValue' => 2], false);
748 }
749
750 /**
751 * @test
752 */
753 public function havingDelegatesToConcreteQueryBuilder()
754 {
755 $this->concreteQueryBuilder->having('uid=1', 'type=9')
756 ->shouldBeCalled()
757 ->willReturn($this->subject);
758
759 $this->subject->having('uid=1', 'type=9');
760 }
761
762 /**
763 * @test
764 */
765 public function andHavingDelegatesToConcreteQueryBuilder()
766 {
767 $this->concreteQueryBuilder->andHaving('uid=1', 'type=9')
768 ->shouldBeCalled()
769 ->willReturn($this->subject);
770
771 $this->subject->andHaving('uid=1', 'type=9');
772 }
773
774 /**
775 * @test
776 */
777 public function orHavingDelegatesToConcreteQueryBuilder()
778 {
779 $this->concreteQueryBuilder->orHaving('uid=1', 'type=9')
780 ->shouldBeCalled()
781 ->willReturn($this->subject);
782
783 $this->subject->orHaving('uid=1', 'type=9');
784 }
785
786 /**
787 * @test
788 */
789 public function orderByQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
790 {
791 $this->connection->quoteIdentifier('aField')
792 ->shouldBeCalled()
793 ->willReturnArgument(0);
794 $this->concreteQueryBuilder->orderBy('aField', null)
795 ->shouldBeCalled()
796 ->willReturn($this->subject);
797
798 $this->subject->orderBy('aField');
799 }
800
801 /**
802 * @test
803 */
804 public function addOrderByQuotesIdentifierAndDelegatesToConcreteQueryBuilder()
805 {
806 $this->connection->quoteIdentifier('aField')
807 ->shouldBeCalled()
808 ->willReturnArgument(0);
809 $this->concreteQueryBuilder->addOrderBy('aField', 'DESC')
810 ->shouldBeCalled()
811 ->willReturn($this->subject);
812
813 $this->subject->addOrderBy('aField', 'DESC');
814 }
815
816 /**
817 * @test
818 */
819 public function getQueryPartDelegatesToConcreteQueryBuilder()
820 {
821 $this->concreteQueryBuilder->getQueryPart('from')
822 ->shouldBeCalled()
823 ->willReturn('aTable');
824
825 $this->subject->getQueryPart('from');
826 }
827
828 /**
829 * @test
830 */
831 public function getQueryPartsDelegatesToConcreteQueryBuilder()
832 {
833 $this->concreteQueryBuilder->getQueryParts()
834 ->shouldBeCalled()
835 ->willReturn([]);
836
837 $this->subject->getQueryParts();
838 }
839
840 /**
841 * @test
842 */
843 public function resetQueryPartsDelegatesToConcreteQueryBuilder()
844 {
845 $this->concreteQueryBuilder->resetQueryParts(['select', 'from'])
846 ->shouldBeCalled()
847 ->willReturn($this->subject);
848
849 $this->subject->resetQueryParts(['select', 'from']);
850 }
851
852 /**
853 * @test
854 */
855 public function resetQueryPartDelegatesToConcreteQueryBuilder()
856 {
857 $this->concreteQueryBuilder->resetQueryPart('select')
858 ->shouldBeCalled()
859 ->willReturn($this->subject);
860
861 $this->subject->resetQueryPart('select');
862 }
863
864 /**
865 * @test
866 */
867 public function createNamedParameterDelegatesToConcreteQueryBuilder()
868 {
869 $this->concreteQueryBuilder->createNamedParameter(5, Argument::cetera())
870 ->shouldBeCalled()
871 ->willReturn(':dcValue1');
872
873 $this->subject->createNamedParameter(5);
874 }
875
876 /**
877 * @test
878 */
879 public function createPositionalParameterDelegatesToConcreteQueryBuilder()
880 {
881 $this->concreteQueryBuilder->createPositionalParameter(5, Argument::cetera())
882 ->shouldBeCalled()
883 ->willReturn('?');
884
885 $this->subject->createPositionalParameter(5);
886 }
887
888 /**
889 * @test
890 */
891 public function queryRestrictionsAreAddedForSelectOnExecute()
892 {
893 $GLOBALS['TCA']['pages']['ctrl'] = [
894 'tstamp' => 'tstamp',
895 'versioningWS' => true,
896 'delete' => 'deleted',
897 'crdate' => 'crdate',
898 'enablecolumns' => [
899 'disabled' => 'hidden',
900 ],
901 ];
902
903 $this->connection->quoteIdentifier(Argument::cetera())
904 ->willReturnArgument(0);
905 $this->connection->quoteIdentifiers(Argument::cetera())
906 ->willReturnArgument(0);
907
908 $connectionBuilder = GeneralUtility::makeInstance(
909 \Doctrine\DBAL\Query\QueryBuilder::class,
910 $this->connection->reveal()
911 );
912
913 $expressionBuilder = GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal());
914 $this->connection->getExpressionBuilder()
915 ->willReturn($expressionBuilder);
916
917 $subject = GeneralUtility::makeInstance(
918 QueryBuilder::class,
919 $this->connection->reveal(),
920 null,
921 $connectionBuilder
922 );
923
924 $subject->select('*')
925 ->from('pages')
926 ->where('uid=1');
927
928 $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
929 $this->connection->executeQuery($expectedSQL, Argument::cetera())
930 ->shouldBeCalled();
931
932 $subject->execute();
933 }
934
935 /**
936 * @test
937 */
938 public function queryRestrictionsAreAddedForCountOnExecute()
939 {
940 $GLOBALS['TCA']['pages']['ctrl'] = [
941 'tstamp' => 'tstamp',
942 'versioningWS' => true,
943 'delete' => 'deleted',
944 'crdate' => 'crdate',
945 'enablecolumns' => [
946 'disabled' => 'hidden',
947 ],
948 ];
949
950 $this->connection->quoteIdentifier(Argument::cetera())
951 ->willReturnArgument(0);
952 $this->connection->quoteIdentifiers(Argument::cetera())
953 ->willReturnArgument(0);
954
955 $connectionBuilder = GeneralUtility::makeInstance(
956 \Doctrine\DBAL\Query\QueryBuilder::class,
957 $this->connection->reveal()
958 );
959
960 $expressionBuilder = GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal());
961 $this->connection->getExpressionBuilder()
962 ->willReturn($expressionBuilder);
963
964 $subject = GeneralUtility::makeInstance(
965 QueryBuilder::class,
966 $this->connection->reveal(),
967 null,
968 $connectionBuilder
969 );
970
971 $subject->count('uid')
972 ->from('pages')
973 ->where('uid=1');
974
975 $expectedSQL = 'SELECT COUNT(uid) FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
976 $this->connection->executeQuery($expectedSQL, Argument::cetera())
977 ->shouldBeCalled();
978
979 $subject->execute();
980 }
981
982 /**
983 * @test
984 */
985 public function queryRestrictionsAreReevaluatedOnSettingsChangeForGetSQL()
986 {
987 $GLOBALS['TCA']['pages']['ctrl'] = [
988 'tstamp' => 'tstamp',
989 'versioningWS' => true,
990 'delete' => 'deleted',
991 'crdate' => 'crdate',
992 'enablecolumns' => [
993 'disabled' => 'hidden',
994 ],
995 ];
996
997 $this->connection->quoteIdentifier(Argument::cetera())
998 ->willReturnArgument(0);
999 $this->connection->quoteIdentifiers(Argument::cetera())
1000 ->willReturnArgument(0);
1001 $this->connection->getExpressionBuilder()
1002 ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
1003
1004 $concreteQueryBuilder = GeneralUtility::makeInstance(
1005 \Doctrine\DBAL\Query\QueryBuilder::class,
1006 $this->connection->reveal()
1007 );
1008
1009 $subject = GeneralUtility::makeInstance(
1010 QueryBuilder::class,
1011 $this->connection->reveal(),
1012 null,
1013 $concreteQueryBuilder
1014 );
1015
1016 $subject->select('*')
1017 ->from('pages')
1018 ->where('uid=1');
1019
1020 $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1021 $this->assertSame($expectedSQL, $subject->getSQL());
1022
1023 $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
1024
1025 $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
1026 $this->assertSame($expectedSQL, $subject->getSQL());
1027 }
1028
1029 /**
1030 * @test
1031 */
1032 public function queryRestrictionsAreReevaluatedOnSettingsChangeForExecute()
1033 {
1034 $GLOBALS['TCA']['pages']['ctrl'] = [
1035 'tstamp' => 'tstamp',
1036 'versioningWS' => true,
1037 'delete' => 'deleted',
1038 'crdate' => 'crdate',
1039 'enablecolumns' => [
1040 'disabled' => 'hidden',
1041 ],
1042 ];
1043
1044 $this->connection->quoteIdentifier(Argument::cetera())
1045 ->willReturnArgument(0);
1046 $this->connection->quoteIdentifiers(Argument::cetera())
1047 ->willReturnArgument(0);
1048 $this->connection->getExpressionBuilder()
1049 ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
1050
1051 $concreteQueryBuilder = GeneralUtility::makeInstance(
1052 \Doctrine\DBAL\Query\QueryBuilder::class,
1053 $this->connection->reveal()
1054 );
1055
1056 $subject = GeneralUtility::makeInstance(
1057 QueryBuilder::class,
1058 $this->connection->reveal(),
1059 null,
1060 $concreteQueryBuilder
1061 );
1062
1063 $subject->select('*')
1064 ->from('pages')
1065 ->where('uid=1');
1066
1067 $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
1068
1069 $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
1070 $this->connection->executeQuery($expectedSQL, Argument::cetera())
1071 ->shouldBeCalled();
1072
1073 $subject->execute();
1074
1075 $subject->resetRestrictions();
1076
1077 $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1078 $this->connection->executeQuery($expectedSQL, Argument::cetera())
1079 ->shouldBeCalled();
1080
1081 $subject->execute();
1082 }
1083 }