TYPO3 CMS  TYPO3_8-7
QueryBuilderTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
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 
33 
34 class QueryBuilderTest extends UnitTestCase
35 {
39  protected $connection;
40 
44  protected $platform;
45 
49  protected $subject;
50 
55 
59  protected function setUp()
60  {
61  parent::setUp();
62 
63  $this->concreteQueryBuilder = $this->prophesize(\Doctrine\DBAL\Query\QueryBuilder::class);
64 
65  $this->connection = $this->prophesize(Connection::class);
66  $this->connection->getDatabasePlatform()->willReturn(new MockPlatform());
67 
68  $this->subject = new QueryBuilder(
69  $this->connection->reveal(),
70  null,
71  $this->concreteQueryBuilder->reveal()
72  );
73  }
74 
79  {
80  $this->connection->getExpressionBuilder()
81  ->shouldBeCalled()
82  ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
83 
84  $this->subject->expr();
85  }
86 
91  {
92  $this->concreteQueryBuilder->getType()
93  ->shouldBeCalled()
94  ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT);
95 
96  $this->subject->getType();
97  }
98 
103  {
104  $this->concreteQueryBuilder->getState()
105  ->shouldBeCalled()
106  ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::STATE_CLEAN);
107 
108  $this->subject->getState();
109  }
110 
115  {
116  $this->concreteQueryBuilder->getSQL()
117  ->shouldBeCalled()
118  ->willReturn('UPDATE aTable SET pid = 7');
119  $this->concreteQueryBuilder->getType()
120  ->willReturn(2); // Update Type
121 
122  $this->subject->getSQL();
123  }
124 
129  {
130  $this->concreteQueryBuilder->setParameter(Argument::exact('aField'), Argument::exact(5), Argument::cetera())
131  ->shouldBeCalled()
132  ->willReturn($this->subject);
133 
134  $this->subject->setParameter('aField', 5);
135  }
136 
141  {
142  $this->concreteQueryBuilder->setParameters(Argument::exact(['aField' => 'aValue']), Argument::exact([]))
143  ->shouldBeCalled()
144  ->willReturn($this->subject);
145 
146  $this->subject->setParameters(['aField' => 'aValue']);
147  }
148 
153  {
154  $this->concreteQueryBuilder->getParameters()
155  ->shouldBeCalled()
156  ->willReturn(['aField' => 'aValue']);
157 
158  $this->subject->getParameters();
159  }
160 
165  {
166  $this->concreteQueryBuilder->getParameter(Argument::exact('aField'))
167  ->shouldBeCalled()
168  ->willReturn('aValue');
169 
170  $this->subject->getParameter('aField');
171  }
172 
177  {
178  $this->concreteQueryBuilder->getParameterTypes()
179  ->shouldBeCalled()
180  ->willReturn([]);
181 
182  $this->subject->getParameterTypes();
183  }
184 
189  {
190  $this->concreteQueryBuilder->getParameterType(Argument::exact('aField'))
191  ->shouldBeCalled()
192  ->willReturn(Connection::PARAM_STR);
193 
194  $this->subject->getParameterType('aField');
195  }
196 
201  {
202  $this->concreteQueryBuilder->setFirstResult(Argument::cetera())
203  ->shouldBeCalled()
204  ->willReturn($this->subject);
205 
206  $this->subject->setFirstResult(1);
207  }
208 
213  {
214  $this->concreteQueryBuilder->getFirstResult()
215  ->shouldBeCalled()
216  ->willReturn(1);
217 
218  $this->subject->getFirstResult();
219  }
220 
225  {
226  $this->concreteQueryBuilder->setMaxResults(Argument::cetera())
227  ->shouldBeCalled()
228  ->willReturn($this->subject);
229 
230  $this->subject->setMaxResults(1);
231  }
232 
237  {
238  $this->concreteQueryBuilder->getMaxResults()
239  ->shouldBeCalled()
240  ->willReturn(1);
241 
242  $this->subject->getMaxResults();
243  }
244 
249  {
250  $this->concreteQueryBuilder->add(Argument::exact('select'), Argument::exact('aField'), Argument::cetera())
251  ->shouldBeCalled()
252  ->willReturn($this->subject);
253 
254  $this->subject->add('select', 'aField');
255  }
256 
261  {
262  $this->concreteQueryBuilder->select(Argument::exact('COUNT(*)'))
263  ->shouldBeCalled()
264  ->willReturn($this->subject);
265 
266  $this->subject->count('*');
267  }
268 
273  {
274  $this->connection->quoteIdentifier('aField')
275  ->shouldBeCalled()
276  ->willReturnArgument(0);
277  $this->connection->quoteIdentifier('anotherField')
278  ->shouldBeCalled()
279  ->willReturnArgument(0);
280  $this->concreteQueryBuilder->select(Argument::exact('aField'), Argument::exact('anotherField'))
281  ->shouldBeCalled()
282  ->willReturn($this->subject);
283 
284  $this->subject->select('aField', 'anotherField');
285  }
286 
291  {
292  return [
293  'fieldName' => [
294  'fieldName',
295  '"fieldName"',
296  ],
297  'tableName.fieldName' => [
298  'tableName.fieldName',
299  '"tableName"."fieldName"',
300  ],
301  'tableName.*' => [
302  'tableName.*',
303  '"tableName".*',
304  ],
305  '*' => [
306  '*',
307  '*',
308  ],
309  'fieldName AS anotherFieldName' => [
310  'fieldName AS anotherFieldName',
311  '"fieldName" AS "anotherFieldName"',
312  ],
313  'tableName.fieldName AS anotherFieldName' => [
314  'tableName.fieldName AS anotherFieldName',
315  '"tableName"."fieldName" AS "anotherFieldName"',
316  ],
317  'tableName.fieldName AS anotherTable.anotherFieldName' => [
318  'tableName.fieldName AS anotherTable.anotherFieldName',
319  '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"',
320  ],
321  'fieldName as anotherFieldName' => [
322  'fieldName as anotherFieldName',
323  '"fieldName" AS "anotherFieldName"',
324  ],
325  'tableName.fieldName as anotherFieldName' => [
326  'tableName.fieldName as anotherFieldName',
327  '"tableName"."fieldName" AS "anotherFieldName"',
328  ],
329  'tableName.fieldName as anotherTable.anotherFieldName' => [
330  'tableName.fieldName as anotherTable.anotherFieldName',
331  '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"',
332  ],
333  'fieldName aS anotherFieldName' => [
334  'fieldName aS anotherFieldName',
335  '"fieldName" AS "anotherFieldName"',
336  ],
337  'tableName.fieldName aS anotherFieldName' => [
338  'tableName.fieldName aS anotherFieldName',
339  '"tableName"."fieldName" AS "anotherFieldName"',
340  ],
341  'tableName.fieldName aS anotherTable.anotherFieldName' => [
342  'tableName.fieldName aS anotherTable.anotherFieldName',
343  '"tableName"."fieldName" AS "anotherTable"."anotherFieldName"',
344  ],
345  ];
346  }
347 
354  public function quoteIdentifiersForSelect($identifier, $expectedResult)
355  {
356  $this->connection->quoteIdentifier(Argument::cetera())->will(
357  function ($args) {
358  $platform = new MockPlatform();
359 
360  return $platform->quoteIdentifier($args[0]);
361  }
362  );
363 
364  $this->assertSame([$expectedResult], $this->subject->quoteIdentifiersForSelect([$identifier]));
365  }
366 
371  {
372  $this->expectException(\InvalidArgumentException::class);
373  $this->expectExceptionCode(1461170686);
374 
375  $this->connection->quoteIdentifier(Argument::cetera())->will(
376  function ($args) {
377  $platform = new MockPlatform();
378 
379  return $platform->quoteIdentifier($args[0]);
380  }
381  );
382  $this->subject->quoteIdentifiersForSelect(['aField AS anotherField,someField AS someThing']);
383  }
384 
389  {
390  $this->connection->quoteIdentifier('aField')
391  ->shouldBeCalled()
392  ->willReturnArgument(0);
393  $this->connection->quoteIdentifier('*')
394  ->shouldNotBeCalled();
395  $this->concreteQueryBuilder->select(Argument::exact('aField'), Argument::exact('*'))
396  ->shouldBeCalled()
397  ->willReturn($this->subject);
398 
399  $this->subject->select('aField', '*');
400  }
401 
406  {
407  $this->connection->quoteIdentifier('aField')
408  ->shouldBeCalled()
409  ->willReturnArgument(0);
410  $this->connection->quoteIdentifier('anotherField')
411  ->shouldBeCalled()
412  ->willReturnArgument(0);
413  $this->concreteQueryBuilder->addSelect(Argument::exact('aField'), Argument::exact('anotherField'))
414  ->shouldBeCalled()
415  ->willReturn($this->subject);
416 
417  $this->subject->addSelect('aField', 'anotherField');
418  }
419 
424  {
425  $this->connection->quoteIdentifier('aField')
426  ->shouldBeCalled()
427  ->willReturnArgument(0);
428  $this->connection->quoteIdentifier('*')
429  ->shouldNotBeCalled();
430  $this->concreteQueryBuilder->addSelect(Argument::exact('aField'), Argument::exact('*'))
431  ->shouldBeCalled()
432  ->willReturn($this->subject);
433 
434  $this->subject->addSelect('aField', '*');
435  }
436 
441  {
442  $this->connection->quoteIdentifier(Argument::cetera())
443  ->shouldNotBeCalled();
444  $this->concreteQueryBuilder->select(Argument::exact('MAX(aField) AS anAlias'))
445  ->shouldBeCalled()
446  ->willReturn($this->subject);
447 
448  $this->subject->selectLiteral('MAX(aField) AS anAlias');
449  }
450 
455  {
456  $this->connection->quoteIdentifier(Argument::cetera())
457  ->shouldNotBeCalled();
458  $this->concreteQueryBuilder->addSelect(Argument::exact('MAX(aField) AS anAlias'))
459  ->shouldBeCalled()
460  ->willReturn($this->subject);
461 
462  $this->subject->addSelectLiteral('MAX(aField) AS anAlias');
463  }
464 
470  {
471  $this->connection->quoteIdentifier('aTable')
472  ->shouldBeCalled()
473  ->willReturnArgument(0);
474  $this->concreteQueryBuilder->delete(Argument::exact('aTable'), Argument::cetera())
475  ->shouldBeCalled()
476  ->willReturn($this->subject);
477 
478  $this->subject->delete('aTable');
479  }
480 
486  {
487  $this->connection->quoteIdentifier('aTable')
488  ->shouldBeCalled()
489  ->willReturnArgument(0);
490  $this->concreteQueryBuilder->update(Argument::exact('aTable'), Argument::cetera())
491  ->shouldBeCalled()
492  ->willReturn($this->subject);
493 
494  $this->subject->update('aTable');
495  }
496 
501  {
502  $this->connection->quoteIdentifier('aTable')
503  ->shouldBeCalled()
504  ->willReturnArgument(0);
505  $this->concreteQueryBuilder->insert(Argument::exact('aTable'))
506  ->shouldBeCalled()
507  ->willReturn($this->subject);
508 
509  $this->subject->insert('aTable');
510  }
511 
517  {
518  $this->connection->quoteIdentifier('aTable')
519  ->shouldBeCalled()
520  ->willReturnArgument(0);
521  $this->concreteQueryBuilder->from(Argument::exact('aTable'), Argument::cetera())
522  ->shouldBeCalled()
523  ->willReturn($this->subject);
524 
525  $this->subject->from('aTable');
526  }
527 
532  {
533  $this->connection->quoteIdentifier('fromAlias')
534  ->shouldBeCalled()
535  ->willReturnArgument(0);
536  $this->connection->quoteIdentifier('join')
537  ->shouldBeCalled()
538  ->willReturnArgument(0);
539  $this->connection->quoteIdentifier('alias')
540  ->shouldBeCalled()
541  ->willReturnArgument(0);
542  $this->concreteQueryBuilder->innerJoin('fromAlias', 'join', 'alias', null)
543  ->shouldBeCalled()
544  ->willReturn($this->subject);
545 
546  $this->subject->join('fromAlias', 'join', 'alias');
547  }
548 
553  {
554  $this->connection->quoteIdentifier('fromAlias')
555  ->shouldBeCalled()
556  ->willReturnArgument(0);
557  $this->connection->quoteIdentifier('join')
558  ->shouldBeCalled()
559  ->willReturnArgument(0);
560  $this->connection->quoteIdentifier('alias')
561  ->shouldBeCalled()
562  ->willReturnArgument(0);
563  $this->concreteQueryBuilder->innerJoin('fromAlias', 'join', 'alias', null)
564  ->shouldBeCalled()
565  ->willReturn($this->subject);
566 
567  $this->subject->innerJoin('fromAlias', 'join', 'alias');
568  }
569 
574  {
575  $this->connection->quoteIdentifier('fromAlias')
576  ->shouldBeCalled()
577  ->willReturnArgument(0);
578  $this->connection->quoteIdentifier('join')
579  ->shouldBeCalled()
580  ->willReturnArgument(0);
581  $this->connection->quoteIdentifier('alias')
582  ->shouldBeCalled()
583  ->willReturnArgument(0);
584  $this->concreteQueryBuilder->leftJoin('fromAlias', 'join', 'alias', null)
585  ->shouldBeCalled()
586  ->willReturn($this->subject);
587 
588  $this->subject->leftJoin('fromAlias', 'join', 'alias');
589  }
590 
595  {
596  $this->connection->quoteIdentifier('fromAlias')
597  ->shouldBeCalled()
598  ->willReturnArgument(0);
599  $this->connection->quoteIdentifier('join')
600  ->shouldBeCalled()
601  ->willReturnArgument(0);
602  $this->connection->quoteIdentifier('alias')
603  ->shouldBeCalled()
604  ->willReturnArgument(0);
605  $this->concreteQueryBuilder->rightJoin('fromAlias', 'join', 'alias', null)
606  ->shouldBeCalled()
607  ->willReturn($this->subject);
608 
609  $this->subject->rightJoin('fromAlias', 'join', 'alias');
610  }
611 
616  {
617  $this->connection->quoteIdentifier('aField')
618  ->shouldBeCalled()
619  ->willReturnArgument(0);
620  $this->concreteQueryBuilder->createNamedParameter('aValue', Argument::cetera())
621  ->shouldBeCalled()
622  ->willReturn(':dcValue1');
623  $this->concreteQueryBuilder->set('aField', ':dcValue1')
624  ->shouldBeCalled()
625  ->willReturn($this->subject);
626 
627  $this->subject->set('aField', 'aValue');
628  }
629 
634  {
635  $this->connection->quoteIdentifier('aField')
636  ->shouldBeCalled()
637  ->willReturnArgument(0);
638  $this->concreteQueryBuilder->createNamedParameter(Argument::cetera())->shouldNotBeCalled();
639  $this->concreteQueryBuilder->set('aField', 'aValue')
640  ->shouldBeCalled()
641  ->willReturn($this->subject);
642 
643  $this->subject->set('aField', 'aValue', false);
644  }
645 
650  {
651  $this->concreteQueryBuilder->where('uid=1', 'type=9')
652  ->shouldBeCalled()
653  ->willReturn($this->subject);
654 
655  $this->subject->where('uid=1', 'type=9');
656  }
657 
662  {
663  $this->concreteQueryBuilder->andWhere('uid=1', 'type=9')
664  ->shouldBeCalled()
665  ->willReturn($this->subject);
666 
667  $this->subject->andWhere('uid=1', 'type=9');
668  }
669 
674  {
675  $this->concreteQueryBuilder->orWhere('uid=1', 'type=9')
676  ->shouldBeCalled()
677  ->willReturn($this->subject);
678 
679  $this->subject->orWhere('uid=1', 'type=9');
680  }
681 
686  {
687  $this->connection->quoteIdentifiers(['aField', 'anotherField'])
688  ->shouldBeCalled()
689  ->willReturnArgument(0);
690  $this->concreteQueryBuilder->groupBy('aField', 'anotherField')
691  ->shouldBeCalled()
692  ->willReturn($this->subject);
693 
694  $this->subject->groupBy('aField', 'anotherField');
695  }
696 
701  {
702  $this->connection->quoteIdentifiers(['aField', 'anotherField'])
703  ->shouldBeCalled()
704  ->willReturnArgument(0);
705  $this->concreteQueryBuilder->addGroupBy('aField', 'anotherField')
706  ->shouldBeCalled()
707  ->willReturn($this->subject);
708 
709  $this->subject->addGroupBy('aField', 'anotherField');
710  }
711 
716  {
717  $this->connection->quoteIdentifier('aField')
718  ->shouldBeCalled()
719  ->willReturnArgument(0);
720  $this->concreteQueryBuilder->createNamedParameter('aValue', Argument::cetera())
721  ->shouldBeCalled()
722  ->willReturn(':dcValue1');
723  $this->concreteQueryBuilder->setValue('aField', ':dcValue1')
724  ->shouldBeCalled()
725  ->willReturn($this->subject);
726 
727  $this->subject->setValue('aField', 'aValue');
728  }
729 
734  {
735  $this->connection->quoteIdentifier('aField')
736  ->shouldBeCalled()
737  ->willReturnArgument(0);
738  $this->concreteQueryBuilder->setValue('aField', 'aValue')
739  ->shouldBeCalled()
740  ->willReturn($this->subject);
741 
742  $this->subject->setValue('aField', 'aValue', false);
743  }
744 
749  {
750  $this->connection->quoteColumnValuePairs(['aField' => ':dcValue1', 'aValue' => ':dcValue2'])
751  ->shouldBeCalled()
752  ->willReturnArgument(0);
753  $this->concreteQueryBuilder->createNamedParameter(1, Argument::cetera())
754  ->shouldBeCalled()
755  ->willReturn(':dcValue1');
756  $this->concreteQueryBuilder->createNamedParameter(2, Argument::cetera())
757  ->shouldBeCalled()
758  ->willReturn(':dcValue2');
759  $this->concreteQueryBuilder->values(['aField' => ':dcValue1', 'aValue' => ':dcValue2'])
760  ->shouldBeCalled()
761  ->willReturn($this->subject);
762 
763  $this->subject->values(['aField' => 1, 'aValue' => 2]);
764  }
765 
770  {
771  $this->connection->quoteColumnValuePairs(['aField' => 1, 'aValue' => 2])
772  ->shouldBeCalled()
773  ->willReturnArgument(0);
774  $this->concreteQueryBuilder->values(['aField' => 1, 'aValue' => 2])
775  ->shouldBeCalled()
776  ->willReturn($this->subject);
777 
778  $this->subject->values(['aField' => 1, 'aValue' => 2], false);
779  }
780 
785  {
786  $this->concreteQueryBuilder->having('uid=1', 'type=9')
787  ->shouldBeCalled()
788  ->willReturn($this->subject);
789 
790  $this->subject->having('uid=1', 'type=9');
791  }
792 
797  {
798  $this->concreteQueryBuilder->andHaving('uid=1', 'type=9')
799  ->shouldBeCalled()
800  ->willReturn($this->subject);
801 
802  $this->subject->andHaving('uid=1', 'type=9');
803  }
804 
809  {
810  $this->concreteQueryBuilder->orHaving('uid=1', 'type=9')
811  ->shouldBeCalled()
812  ->willReturn($this->subject);
813 
814  $this->subject->orHaving('uid=1', 'type=9');
815  }
816 
821  {
822  $this->connection->quoteIdentifier('aField')
823  ->shouldBeCalled()
824  ->willReturnArgument(0);
825  $this->concreteQueryBuilder->orderBy('aField', null)
826  ->shouldBeCalled()
827  ->willReturn($this->subject);
828 
829  $this->subject->orderBy('aField');
830  }
831 
836  {
837  $this->connection->quoteIdentifier('aField')
838  ->shouldBeCalled()
839  ->willReturnArgument(0);
840  $this->concreteQueryBuilder->addOrderBy('aField', 'DESC')
841  ->shouldBeCalled()
842  ->willReturn($this->subject);
843 
844  $this->subject->addOrderBy('aField', 'DESC');
845  }
846 
851  {
852  $this->concreteQueryBuilder->getQueryPart('from')
853  ->shouldBeCalled()
854  ->willReturn('aTable');
855 
856  $this->subject->getQueryPart('from');
857  }
858 
863  {
864  $this->concreteQueryBuilder->getQueryParts()
865  ->shouldBeCalled()
866  ->willReturn([]);
867 
868  $this->subject->getQueryParts();
869  }
870 
875  {
876  $this->concreteQueryBuilder->resetQueryParts(['select', 'from'])
877  ->shouldBeCalled()
878  ->willReturn($this->subject);
879 
880  $this->subject->resetQueryParts(['select', 'from']);
881  }
882 
887  {
888  $this->concreteQueryBuilder->resetQueryPart('select')
889  ->shouldBeCalled()
890  ->willReturn($this->subject);
891 
892  $this->subject->resetQueryPart('select');
893  }
894 
899  {
900  $this->concreteQueryBuilder->createNamedParameter(5, Argument::cetera())
901  ->shouldBeCalled()
902  ->willReturn(':dcValue1');
903 
904  $this->subject->createNamedParameter(5);
905  }
906 
911  {
912  $this->concreteQueryBuilder->createPositionalParameter(5, Argument::cetera())
913  ->shouldBeCalled()
914  ->willReturn('?');
915 
916  $this->subject->createPositionalParameter(5);
917  }
918 
923  {
924  $GLOBALS['TCA']['pages']['ctrl'] = [
925  'tstamp' => 'tstamp',
926  'versioningWS' => true,
927  'delete' => 'deleted',
928  'crdate' => 'crdate',
929  'enablecolumns' => [
930  'disabled' => 'hidden',
931  ],
932  ];
933 
934  $this->connection->quoteIdentifier(Argument::cetera())
935  ->willReturnArgument(0);
936  $this->connection->quoteIdentifiers(Argument::cetera())
937  ->willReturnArgument(0);
938 
939  $connectionBuilder = GeneralUtility::makeInstance(
940  \Doctrine\DBAL\Query\QueryBuilder::class,
941  $this->connection->reveal()
942  );
943 
944  $expressionBuilder = GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal());
945  $this->connection->getExpressionBuilder()
946  ->willReturn($expressionBuilder);
947 
949  QueryBuilder::class,
950  $this->connection->reveal(),
951  null,
952  $connectionBuilder
953  );
954 
955  $subject->select('*')
956  ->from('pages')
957  ->where('uid=1');
958 
959  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
960  $this->connection->executeQuery($expectedSQL, Argument::cetera())
961  ->shouldBeCalled();
962 
963  $subject->execute();
964  }
965 
970  {
971  $GLOBALS['TCA']['pages']['ctrl'] = [
972  'tstamp' => 'tstamp',
973  'versioningWS' => true,
974  'delete' => 'deleted',
975  'crdate' => 'crdate',
976  'enablecolumns' => [
977  'disabled' => 'hidden',
978  ],
979  ];
980 
981  $this->connection->quoteIdentifier(Argument::cetera())
982  ->willReturnArgument(0);
983  $this->connection->quoteIdentifiers(Argument::cetera())
984  ->willReturnArgument(0);
985 
986  $connectionBuilder = GeneralUtility::makeInstance(
987  \Doctrine\DBAL\Query\QueryBuilder::class,
988  $this->connection->reveal()
989  );
990 
991  $expressionBuilder = GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal());
992  $this->connection->getExpressionBuilder()
993  ->willReturn($expressionBuilder);
994 
996  QueryBuilder::class,
997  $this->connection->reveal(),
998  null,
999  $connectionBuilder
1000  );
1001 
1002  $subject->count('uid')
1003  ->from('pages')
1004  ->where('uid=1');
1005 
1006  $expectedSQL = 'SELECT COUNT(uid) FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1007  $this->connection->executeQuery($expectedSQL, Argument::cetera())
1008  ->shouldBeCalled();
1009 
1010  $subject->execute();
1011  }
1012 
1017  {
1018  $GLOBALS['TCA']['pages']['ctrl'] = [
1019  'tstamp' => 'tstamp',
1020  'versioningWS' => true,
1021  'delete' => 'deleted',
1022  'crdate' => 'crdate',
1023  'enablecolumns' => [
1024  'disabled' => 'hidden',
1025  ],
1026  ];
1027 
1028  $this->connection->quoteIdentifier(Argument::cetera())
1029  ->willReturnArgument(0);
1030  $this->connection->quoteIdentifiers(Argument::cetera())
1031  ->willReturnArgument(0);
1032  $this->connection->getExpressionBuilder()
1033  ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
1034 
1036  \Doctrine\DBAL\Query\QueryBuilder::class,
1037  $this->connection->reveal()
1038  );
1039 
1041  QueryBuilder::class,
1042  $this->connection->reveal(),
1043  null,
1045  );
1046 
1047  $subject->select('*')
1048  ->from('pages')
1049  ->where('uid=1');
1050 
1051  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1052  $this->assertSame($expectedSQL, $subject->getSQL());
1053 
1054  $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
1055 
1056  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
1057  $this->assertSame($expectedSQL, $subject->getSQL());
1058  }
1059 
1064  {
1065  $GLOBALS['TCA']['pages']['ctrl'] = [
1066  'tstamp' => 'tstamp',
1067  'versioningWS' => true,
1068  'delete' => 'deleted',
1069  'crdate' => 'crdate',
1070  'enablecolumns' => [
1071  'disabled' => 'hidden',
1072  ],
1073  ];
1074 
1075  $this->connection->quoteIdentifier(Argument::cetera())
1076  ->willReturnArgument(0);
1077  $this->connection->quoteIdentifiers(Argument::cetera())
1078  ->willReturnArgument(0);
1079  $this->connection->getExpressionBuilder()
1080  ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
1081 
1083  \Doctrine\DBAL\Query\QueryBuilder::class,
1084  $this->connection->reveal()
1085  );
1086 
1088  QueryBuilder::class,
1089  $this->connection->reveal(),
1090  null,
1092  );
1093 
1094  $subject->select('*')
1095  ->from('pages')
1096  ->where('uid=1');
1097 
1098  $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
1099 
1100  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
1101  $this->connection->executeQuery($expectedSQL, Argument::cetera())
1102  ->shouldBeCalled();
1103 
1104  $subject->execute();
1105 
1106  $subject->resetRestrictions();
1107 
1108  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1109  $this->connection->executeQuery($expectedSQL, Argument::cetera())
1110  ->shouldBeCalled();
1111 
1112  $subject->execute();
1113  }
1114 
1119  {
1120  $this->concreteQueryBuilder->getQueryPart('from')
1121  ->shouldBeCalled()
1122  ->willReturn([
1123  [
1124  'table' => 'aTable',
1125  ],
1126  ]);
1127  $this->concreteQueryBuilder->getQueryPart('join')
1128  ->shouldBeCalled()
1129  ->willReturn([
1130  'aTable' => [
1131  [
1132  'joinType' => 'inner',
1133  'joinTable' => 'aTable',
1134  'joinAlias' => 'aTable_alias'
1135  ]
1136  ]
1137  ]);
1138  $result = $this->callInaccessibleMethod($this->subject, 'getQueriedTables');
1139 
1140  $expected = [
1141  'aTable' => 'aTable',
1142  'aTable_alias' => 'aTable'
1143  ];
1144  $this->assertEquals($expected, $result);
1145  }
1146 
1151  {
1152  return [
1153  'mysql' => [
1154  'platform' => MySqlPlatform::class,
1155  'quoteChar' => '`',
1156  'input' => '`anIdentifier`',
1157  'expected' => 'anIdentifier',
1158  ],
1159  'mysql with spaces' => [
1160  'platform' => MySqlPlatform::class,
1161  'quoteChar' => '`',
1162  'input' => ' `anIdentifier` ',
1163  'expected' => 'anIdentifier',
1164  ],
1165  'postgres' => [
1166  'platform' => PostgreSqlPlatform::class,
1167  'quoteChar' => '"',
1168  'input' => '"anIdentifier"',
1169  'expected' => 'anIdentifier',
1170  ],
1171  'mssql' => [
1172  'platform' => SQLServerPlatform::class,
1173  'quoteChar' => '', // no single quote character, but [ and ]
1174  'input' => '[anIdentifier]',
1175  'expected' => 'anIdentifier',
1176  ],
1177  ];
1178  }
1179 
1184  public function unquoteSingleIdentifierUnquotesCorrectlyOnDifferentPlatforms($platform, $quoteChar, $input, $expected)
1185  {
1186  $connectionProphecy = $this->prophesize(Connection::class);
1187  $databasePlatformProphecy = $this->prophesize($platform);
1188  $databasePlatformProphecy->getIdentifierQuoteCharacter()->willReturn($quoteChar);
1189  $connectionProphecy->getDatabasePlatform()->willReturn($databasePlatformProphecy);
1190  $subject = GeneralUtility::makeInstance(QueryBuilder::class, $connectionProphecy->reveal());
1191  $result = $this->callInaccessibleMethod($subject, 'unquoteSingleIdentifier', $input);
1192  $this->assertEquals($expected, $result);
1193  }
1194 
1199  {
1200  $clonedQueryBuilder = clone $this->subject;
1201  self::assertNotSame($this->subject->getConcreteQueryBuilder(), $clonedQueryBuilder->getConcreteQueryBuilder());
1202  }
1203 
1208  {
1209  $GLOBALS['TCA']['pages']['ctrl'] = [
1210  'tstamp' => 'tstamp',
1211  'versioningWS' => true,
1212  'delete' => 'deleted',
1213  'crdate' => 'crdate',
1214  'enablecolumns' => [
1215  'disabled' => 'hidden',
1216  ],
1217  ];
1218 
1219  $this->connection->quoteIdentifier(Argument::cetera())
1220  ->willReturnArgument(0);
1221  $this->connection->quoteIdentifiers(Argument::cetera())
1222  ->willReturnArgument(0);
1223  $this->connection->getExpressionBuilder()
1224  ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection->reveal()));
1225 
1227  \Doctrine\DBAL\Query\QueryBuilder::class,
1228  $this->connection->reveal()
1229  );
1230 
1232  QueryBuilder::class,
1233  $this->connection->reveal(),
1234  null,
1236  );
1237 
1238  $subject->select('*')
1239  ->from('pages')
1240  ->where('uid=1');
1241 
1242  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1243  $this->assertSame($expectedSQL, $subject->getSQL());
1244 
1245  $clonedQueryBuilder = clone $subject;
1246  //just after cloning both query builders should return the same sql
1247  $this->assertSame($expectedSQL, $clonedQueryBuilder->getSQL());
1248 
1249  //change cloned QueryBuilder
1250  $clonedQueryBuilder->count('*');
1251  $expectedCountSQL = 'SELECT COUNT(*) FROM pages WHERE (uid=1) AND ((pages.deleted = 0) AND (pages.hidden = 0))';
1252  $this->assertSame($expectedCountSQL, $clonedQueryBuilder->getSQL());
1253 
1254  //check if the original QueryBuilder has not changed
1255  $this->assertSame($expectedSQL, $subject->getSQL());
1256 
1257  //change restrictions in the original QueryBuilder and check if cloned has changed
1258  $subject->getRestrictions()->removeAll()->add(new DeletedRestriction());
1259  $expectedSQL = 'SELECT * FROM pages WHERE (uid=1) AND (pages.deleted = 0)';
1260  $this->assertSame($expectedSQL, $subject->getSQL());
1261 
1262  $this->assertSame($expectedCountSQL, $clonedQueryBuilder->getSQL());
1263  }
1264 
1269  {
1270  $restrictionClass = get_class($this->prophesize(QueryRestrictionInterface::class)->reveal());
1271  $queryBuilder = new QueryBuilder(
1272  $this->connection->reveal(),
1273  null,
1274  $this->concreteQueryBuilder->reveal(),
1275  [
1276  $restrictionClass => [],
1277  ]
1278  );
1279 
1280  $container = $this->prophesize(AbstractRestrictionContainer::class);
1281  $container->add(new $restrictionClass())->shouldBeCalled();
1282 
1283  $queryBuilder->setRestrictions($container->reveal());
1284  }
1285 
1290  {
1291  $restrictionClass = get_class($this->prophesize(QueryRestrictionInterface::class)->reveal());
1292  $GLOBALS['TYPO3_CONF_VARS']['DB']['additionalQueryRestrictions'][$restrictionClass] = [];
1293  $queryBuilder = new QueryBuilder(
1294  $this->connection->reveal(),
1295  null,
1296  $this->concreteQueryBuilder->reveal()
1297  );
1298 
1299  $container = $this->prophesize(AbstractRestrictionContainer::class);
1300  $container->add(new $restrictionClass())->shouldBeCalled();
1301 
1302  $queryBuilder->setRestrictions($container->reveal());
1303  }
1304 
1309  {
1310  $restrictionClass = get_class($this->prophesize(QueryRestrictionInterface::class)->reveal());
1311  $GLOBALS['TYPO3_CONF_VARS']['DB']['additionalQueryRestrictions'][$restrictionClass] = ['disabled' => true];
1312  $queryBuilder = new QueryBuilder(
1313  $this->connection->reveal(),
1314  null,
1315  $this->concreteQueryBuilder->reveal()
1316  );
1317 
1318  $container = $this->prophesize(AbstractRestrictionContainer::class);
1319  $container->add(new $restrictionClass())->shouldNotBeCalled();
1320 
1321  $queryBuilder->setRestrictions($container->reveal());
1322  }
1323 
1328  {
1329  $restrictionClass = get_class($this->prophesize(QueryRestrictionInterface::class)->reveal());
1330  $queryBuilder = new QueryBuilder(
1331  $this->connection->reveal(),
1332  null,
1333  $this->concreteQueryBuilder->reveal(),
1334  [
1335  $restrictionClass => [],
1336  ]
1337  );
1338 
1339  $container = $this->prophesize(DefaultRestrictionContainer::class);
1340  $container->add(new $restrictionClass())->shouldBeCalled();
1341  GeneralUtility::addInstance(DefaultRestrictionContainer::class, $container->reveal());
1342 
1343  $queryBuilder->resetRestrictions();
1344  }
1345 }
static addInstance($className, $instance)
unquoteSingleIdentifierUnquotesCorrectlyOnDifferentPlatforms($platform, $quoteChar, $input, $expected)
static makeInstance($className,... $constructorArguments)
add(string $sqlPartName, string $sqlPart, bool $append=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']