TYPO3 CMS  TYPO3_8-7
Typo3DbQueryParserTest.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
34 
35 class Typo3DbQueryParserTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
36 {
41 
45  protected function setUp()
46  {
47  parent::setUp();
48  $this->singletonInstances = GeneralUtility::getSingletonInstances();
49  }
50 
54  protected function tearDown()
55  {
57  GeneralUtility::resetSingletonInstances($this->singletonInstances);
58  parent::tearDown();
59  }
60 
65  {
66  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
67  $subject = $this->getAccessibleMock(
68  Typo3DbQueryParser::class,
69  // Shut down some methods not important for this test
70  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints']
71  );
72  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
73  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
74 
75  $queryProphecy = $this->prophesize(QueryInterface::class);
76  $sourceProphecy = $this->prophesize(SourceInterface::class);
77  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
78  $queryProphecy->getOrderings()->willReturn([]);
79  $queryProphecy->getStatement()->willReturn(null);
80 
81  // Test part: getConstraint returns no constraint object, andWhere() should not be called
82  $queryProphecy->getConstraint()->willReturn(null);
83  $queryBuilderProphecy->andWhere()->shouldNotBeCalled();
84 
85  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
86  }
87 
92  {
93  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
94  $subject = $this->getAccessibleMock(
95  Typo3DbQueryParser::class,
96  // Shut down some methods not important for this test
97  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
98  );
99  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
100  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
101 
102  $queryProphecy = $this->prophesize(QueryInterface::class);
103  $sourceProphecy = $this->prophesize(SourceInterface::class);
104  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
105  $queryProphecy->getOrderings()->willReturn([]);
106  $queryProphecy->getStatement()->willReturn(null);
107 
108  // Test part: getConstraint returns not implemented object
109  $constraintProphecy = $this->prophesize(ConstraintInterface::class);
110  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
111 
112  $this->expectException(\RuntimeException::class);
113  $this->expectExceptionCode(1476199898);
114  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
115  }
116 
121  {
122  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
123  $subject = $this->getAccessibleMock(
124  Typo3DbQueryParser::class,
125  // Shut down some methods not important for this test
126  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
127  );
128  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
129  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
130 
131  $queryProphecy = $this->prophesize(QueryInterface::class);
132  $sourceProphecy = $this->prophesize(SourceInterface::class);
133  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
134  $queryProphecy->getOrderings()->willReturn([]);
135  $queryProphecy->getStatement()->willReturn(null);
136 
137  // Test part: getConstraint returns simple constraint, and should push to andWhere()
138  $constraintProphecy = $this->prophesize(ComparisonInterface::class);
139  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
140  $subject->expects($this->once())->method('parseComparison')->willReturn('heinz');
141  $queryBuilderProphecy->andWhere('heinz')->shouldBeCalled();
142 
143  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
144  }
145 
150  {
151  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
152  $subject = $this->getAccessibleMock(
153  Typo3DbQueryParser::class,
154  // Shut down some methods not important for this test
155  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
156  );
157  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
158  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
159 
160  $queryProphecy = $this->prophesize(QueryInterface::class);
161  $sourceProphecy = $this->prophesize(SourceInterface::class);
162  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
163  $queryProphecy->getOrderings()->willReturn([]);
164  $queryProphecy->getStatement()->willReturn(null);
165 
166  $constraintProphecy = $this->prophesize(NotInterface::class);
167  $subConstraintProphecy = $this->prophesize(ComparisonInterface::class);
168  $constraintProphecy->getConstraint()->shouldBeCalled()->willReturn($subConstraintProphecy->reveal());
169  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
170  $subject->expects($this->once())->method('parseComparison')->willReturn('heinz');
171  $queryBuilderProphecy->andWhere(' NOT(heinz)')->shouldBeCalled();
172 
173  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
174  }
175 
180  {
181  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
182  $subject = $this->getAccessibleMock(
183  Typo3DbQueryParser::class,
184  // Shut down some methods not important for this test
185  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
186  );
187  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
188  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
189 
190  $queryProphecy = $this->prophesize(QueryInterface::class);
191  $sourceProphecy = $this->prophesize(SourceInterface::class);
192  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
193  $queryProphecy->getOrderings()->willReturn([]);
194  $queryProphecy->getStatement()->willReturn(null);
195 
196  $constraintProphecy = $this->prophesize(AndInterface::class);
197  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
198  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
199  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
200  $constraint2Prophecy = $this->prophesize(ComparisonInterface::class);
201  $constraintProphecy->getConstraint2()->willReturn($constraint2Prophecy->reveal());
202  $subject->expects($this->any())->method('parseComparison')->willReturn('heinz');
203  $expressionProphecy = $this->prophesize(ExpressionBuilder::class);
204  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionProphecy->reveal());
205  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
206  $compositeExpressionProphecy->__toString()->willReturn('heinz AND heinz');
207  $compositeExpressionRevelation = $compositeExpressionProphecy->reveal();
208  $expressionProphecy->andX('heinz', 'heinz')->shouldBeCalled()->willReturn($compositeExpressionRevelation);
209  $queryBuilderProphecy->andWhere($compositeExpressionRevelation)->shouldBeCalled();
210 
211  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
212  }
213 
218  {
219  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
220  $subject = $this->getAccessibleMock(
221  Typo3DbQueryParser::class,
222  // Shut down some methods not important for this test
223  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
224  );
225  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
226  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
227 
228  $queryProphecy = $this->prophesize(QueryInterface::class);
229  $sourceProphecy = $this->prophesize(SourceInterface::class);
230  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
231  $queryProphecy->getOrderings()->willReturn([]);
232  $queryProphecy->getStatement()->willReturn(null);
233 
234  $constraintProphecy = $this->prophesize(AndInterface::class);
235  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
236  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
237  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
238  // no result for constraint2
239  $constraintProphecy->getConstraint2()->willReturn(null);
240 
241  // not be called
242  $queryBuilderProphecy->andWhere()->shouldNotBeCalled();
243 
244  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
245  }
246 
251  {
252  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
253  $subject = $this->getAccessibleMock(
254  Typo3DbQueryParser::class,
255  // Shut down some methods not important for this test
256  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
257  );
258  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
259  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
260 
261  $queryProphecy = $this->prophesize(QueryInterface::class);
262  $sourceProphecy = $this->prophesize(SourceInterface::class);
263  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
264  $queryProphecy->getOrderings()->willReturn([]);
265  $queryProphecy->getStatement()->willReturn(null);
266 
267  $constraintProphecy = $this->prophesize(OrInterface::class);
268  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
269  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
270  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
271  $constraint2Prophecy = $this->prophesize(ComparisonInterface::class);
272  $constraintProphecy->getConstraint2()->willReturn($constraint2Prophecy->reveal());
273  $subject->expects($this->any())->method('parseComparison')->willReturn('heinz');
274  $expressionProphecy = $this->prophesize(ExpressionBuilder::class);
275  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionProphecy->reveal());
276  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
277  $compositeExpressionProphecy->__toString()->willReturn('heinz OR heinz');
278  $compositeExpressionRevelation = $compositeExpressionProphecy->reveal();
279  $expressionProphecy->orX('heinz', 'heinz')->shouldBeCalled()->willReturn($compositeExpressionRevelation);
280  $queryBuilderProphecy->andWhere($compositeExpressionRevelation)->shouldBeCalled();
281 
282  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
283  }
284 
289  {
290  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
291  $subject = $this->getAccessibleMock(
292  Typo3DbQueryParser::class,
293  // Shut down some methods not important for this test
294  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
295  );
296  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
297  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
298 
299  $queryProphecy = $this->prophesize(QueryInterface::class);
300  $sourceProphecy = $this->prophesize(SourceInterface::class);
301  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
302  $queryProphecy->getOrderings()->willReturn([]);
303  $queryProphecy->getStatement()->willReturn(null);
304 
305  $constraintProphecy = $this->prophesize(OrInterface::class);
306  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
307  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
308  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
309  // no result for constraint2
310  $constraintProphecy->getConstraint2()->willReturn(null);
311 
312  // not be called
313  $queryBuilderProphecy->andWhere()->shouldNotBeCalled();
314 
315  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
316  }
317 
322  {
323  $connectionProphet = $this->prophesize(Connection::class);
324  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
325  $querBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
326  $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
327  $querBuilderProphet->expr()->willReturn($expr);
328  return $querBuilderProphet;
329  }
330 
335  {
336  $connectionProphet = $this->prophesize(Connection::class);
337  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
338  $queryBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
339  $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
340  $queryBuilderProphet->expr()->willReturn(
341  $expr
342  );
343  $queryBuilderProphet->getConnection()->willReturn($connectionProphet->reveal());
344  $queryBuilderForSubselectMock = $this->getMockBuilder(QueryBuilder::class)
345  ->setMethods(['expr', 'unquoteSingleIdentifier'])
346  ->setConstructorArgs([$connectionProphet->reveal()])
347  ->getMock();
348  $connectionProphet->createQueryBuilder()->willReturn($queryBuilderForSubselectMock);
349  $queryBuilderForSubselectMock->expects($this->any())->method('expr')->will($this->returnValue($expr));
350  $queryBuilderForSubselectMock->expects($this->any())->method('unquoteSingleIdentifier')->will($this->returnCallback(function ($identifier) {
351  return $identifier;
352  }));
353  return $queryBuilderProphet;
354  }
355 
359  public function addSysLanguageStatementWorksForDefaultLanguage()
360  {
361  $table = $this->getUniqueId('tx_coretest_table');
362  $GLOBALS['TCA'][$table]['ctrl'] = [
363  'languageField' => 'sys_language_uid'
364  ];
366  $querySettings = $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class);
367  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
368  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
369  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
370  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
371  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
372  $this->assertSame($expectedSql, $sql);
373  }
374 
378  public function addSysLanguageStatementWorksForNonDefaultLanguage()
379  {
380  $table = $this->getUniqueId('tx_coretest_table');
381  $GLOBALS['TCA'][$table]['ctrl'] = [
382  'languageField' => 'sys_language_uid'
383  ];
385  $querySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
386  ->setMethods(['dummy'])
387  ->getMock();
388  $querySettings->setLanguageUid('1');
389  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
390  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
391  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
392  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
393  $result = $table . '.sys_language_uid IN (1, -1)';
394  $this->assertSame($result, $sql);
395  }
396 
401  {
402  $table = $this->getUniqueId('tx_coretest_table');
403  $GLOBALS['TCA'][$table]['ctrl'] = [
404  'languageField' => 'sys_language_uid'
405  ];
406  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
407  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
408  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
409  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
410  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
411  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
412  $this->assertSame($expectedSql, $sql);
413  }
414 
419  {
420  $table = $this->getUniqueId('tx_coretest_table');
421  $GLOBALS['TCA'][$table]['ctrl'] = [
422  'languageField' => 'sys_language_uid',
423  'delete' => 'deleted'
424  ];
425  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
426  $querySettings->setLanguageUid(0);
427  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
428  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
429  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
430  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
431  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
432  $this->assertSame($expectedSql, $sql);
433  }
434 
439  {
440  $table = $this->getUniqueId('tx_coretest_table');
441  $GLOBALS['TCA'][$table]['ctrl'] = [
442  'languageField' => 'sys_language_uid'
443  ];
444  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
445  $querySettings->setLanguageUid(2);
446  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
447  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
448  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
449  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
450  $expectedSql = $table . '.sys_language_uid IN (2, -1)';
451  $this->assertSame($expectedSql, $sql);
452  }
453 
458  {
459  $table = $this->getUniqueId('tx_coretest_table');
460  $GLOBALS['TCA'][$table]['ctrl'] = [
461  'languageField' => 'sys_language_uid',
462  'transOrigPointerField' => 'l10n_parent'
463  ];
464  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
465  $querySettings->setLanguageUid(2);
466  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
467 
468  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
469 
470  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
471 
472  $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
473  $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1)) OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (SELECT ' . $table . '.l10n_parent FROM ' . $table . ' WHERE (' . $table . '.l10n_parent > 0) AND (' . $table . '.sys_language_uid = 2))))';
474  $this->assertSame($expectedSql, $compositeExpression->__toString());
475  }
476 
481  {
482  $table = $this->getUniqueId('tx_coretest_table');
483  $GLOBALS['TCA'][$table]['ctrl'] = [
484  'languageField' => 'sys_language_uid',
485  'transOrigPointerField' => 'l10n_parent',
486  'delete' => 'deleted'
487  ];
488  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
489  $querySettings->setLanguageUid(2);
490  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
491  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
492  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
493  $compositeExpression= $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
494  $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
495  ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
496  'SELECT ' . $table . '.l10n_parent FROM ' . $table .
497  ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
498  $table . '.sys_language_uid = 2) AND (' .
499  $table . '.deleted = 0))))';
500  $this->assertSame($expectedSql, $compositeExpression->__toString());
501  }
502 
507  {
508  $table = 'tt_content';
509  $GLOBALS['TCA'][$table]['ctrl'] = [
510  'languageField' => 'sys_language_uid',
511  'transOrigPointerField' => 'l10n_parent',
512  'delete' => 'deleted'
513  ];
514  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
515  $querySettings->setLanguageUid(2);
516  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
517 
518  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
519 
520  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
521  $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
522  $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
523  ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
524  'SELECT ' . $table . '.l10n_parent FROM ' . $table .
525  ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
526  $table . '.sys_language_uid = 2) AND (' .
527  $table . '.deleted = 0))))';
528  $this->assertSame($expectedSql, $compositeExpression->__toString());
529  }
530 
535  {
536  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
537  ->setMethods(['getNodeTypeName'])
538  ->disableOriginalConstructor()
539  ->getMock();
540  $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('foo'));
541  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
542  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
543  ->disableOriginalConstructor()
544  ->getMock();
545  $mockDataMapper->expects($this->once())->method('convertClassNameToTableName')->with('foo')->will($this->returnValue('tx_myext_tablename'));
546  $mockDataMapper->expects($this->once())->method('convertPropertyNameToColumnName')->with('fooProperty', 'foo')->will($this->returnValue('converted_fieldname'));
547  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
548  $queryBuilderProphet->addOrderBy('tx_myext_tablename.converted_fieldname', 'ASC')->shouldBeCalledTimes(1);
549 
550  $orderings = ['fooProperty' => QueryInterface::ORDER_ASCENDING];
551  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
552  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
553  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
554  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
555  }
556 
561  {
562  $this->expectException(UnsupportedOrderException::class);
563  $this->expectExceptionCode(1242816074);
564  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
565  ->setMethods(['getNodeTypeName'])
566  ->disableOriginalConstructor()
567  ->getMock();
568  $mockSource->expects($this->never())->method('getNodeTypeName');
569  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
570  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
571  ->disableOriginalConstructor()
572  ->getMock();
573  $mockDataMapper->expects($this->never())->method('convertClassNameToTableName');
574  $mockDataMapper->expects($this->never())->method('convertPropertyNameToColumnName');
575  $orderings = ['fooProperty' => 'unsupported_order'];
576  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
577  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
578 
579  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
580  }
581 
586  {
587  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
588  ->setMethods(['getNodeTypeName'])
589  ->disableOriginalConstructor()
590  ->getMock();
591  $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('Tx_MyExt_ClassName'));
592  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
593  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
594  ->disableOriginalConstructor()
595  ->getMock();
596  $mockDataMapper->expects($this->any())->method('convertClassNameToTableName')->with('Tx_MyExt_ClassName')->will($this->returnValue('tx_myext_tablename'));
597  $mockDataMapper->expects($this->any())->method('convertPropertyNameToColumnName')->will($this->returnValue('converted_fieldname'));
598  $orderings = [
599  'fooProperty' => QueryInterface::ORDER_ASCENDING,
600  'barProperty' => QueryInterface::ORDER_DESCENDING
601  ];
602  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
603  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
604 
605  $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
606  ->disableOriginalConstructor()
607  ->setMethods(['addOrderBy'])
608  ->getMock();
609  $queryBuilder->expects($this->at(0))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'ASC');
610  $queryBuilder->expects($this->at(1))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'DESC');
611 
612  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilder);
613  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
614  }
615 
617  {
618  return [
619  'in be: include all' => ['BE', true, [], true, ''],
620  'in be: ignore enable fields but do not include deleted' => ['BE', true, [], false, 'tx_foo_table.deleted_column = 0'],
621  'in be: respect enable fields but include deleted' => ['BE', false, [], true, '(tx_foo_table.disabled_column = 0) AND (tx_foo_table.starttime_column <= 123456789)'],
622  'in be: respect enable fields and do not include deleted' => ['BE', false, [], false, '(tx_foo_table.disabled_column = 0) AND (tx_foo_table.starttime_column <= 123456789) AND tx_foo_table.deleted_column = 0'],
623  'in fe: include all' => ['FE', true, [], true, ''],
624  'in fe: ignore enable fields but do not include deleted' => ['FE', true, [], false, 'tx_foo_table.deleted_column=0'],
625  'in fe: ignore only starttime and do not include deleted' => ['FE', true, ['starttime'], false, '(tx_foo_table.deleted_column = 0) AND (tx_foo_table.disabled_column = 0)'],
626  'in fe: respect enable fields and do not include deleted' => ['FE', false, [], false, '(tx_foo_table.deleted_column = 0) AND (tx_foo_table.disabled_column = 0) AND (tx_foo_table.starttime_column <= 123456789)']
627  ];
628  }
629 
634  public function visibilityConstraintStatementIsGeneratedAccordingToTheQuerySettings($mode, $ignoreEnableFields, $enableFieldsToBeIgnored, $deletedValue, $expectedSql)
635  {
636  $tableName = 'tx_foo_table';
637  $GLOBALS['TCA'][$tableName]['ctrl'] = [
638  'enablecolumns' => [
639  'disabled' => 'disabled_column',
640  'starttime' => 'starttime_column'
641  ],
642  'delete' => 'deleted_column'
643  ];
644  $GLOBALS['TSFE'] = new \stdClass();
645  $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
646  $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
647 
648  $connectionProphet = $this->prophesize(Connection::class);
649  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
650  $connectionProphet->getExpressionBuilder()->willReturn(
651  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
652  );
653 
654  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
655  $queryBuilderProphet->expr()->willReturn(
656  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
657  );
658  $queryBuilderProphet->createNamedParameter(Argument::cetera())->willReturnArgument(0);
659 
660  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
661  $connectionPoolProphet->getConnectionForTable(Argument::any($tableName, 'pages'))->willReturn($connectionProphet->reveal());
662  $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
663  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
664  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
665 
666  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
667  ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
668  ->disableOriginalConstructor()
669  ->getMock();
670  $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue($ignoreEnableFields));
671  $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue($enableFieldsToBeIgnored));
672  $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue($deletedValue));
673 
675  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
676  ->setMethods(['isEnvironmentInFrontendMode'])
677  ->getMock();
678  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode === 'FE'));
679 
680  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
681  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
682  $resultSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
683  $this->assertSame($expectedSql, $resultSql);
684  unset($GLOBALS['TCA'][$tableName]);
685  }
686 
688  {
689  return [
690  'in be: respectEnableFields=false' => ['BE', false, ''],
691  'in be: respectEnableFields=true' => ['BE', true, '(tx_foo_table.disabled_column = 0) AND (tx_foo_table.starttime_column <= 123456789) AND tx_foo_table.deleted_column = 0'],
692  'in FE: respectEnableFields=false' => ['FE', false, ''],
693  'in FE: respectEnableFields=true' => ['FE', true, '(tx_foo_table.deleted_column = 0) AND (tx_foo_table.disabled_column = 0) AND (tx_foo_table.starttime_column <= 123456789)']
694  ];
695  }
696 
701  public function respectEnableFieldsSettingGeneratesCorrectStatement($mode, $respectEnableFields, $expectedSql)
702  {
703  $tableName = 'tx_foo_table';
704  $GLOBALS['TCA'][$tableName]['ctrl'] = [
705  'enablecolumns' => [
706  'disabled' => 'disabled_column',
707  'starttime' => 'starttime_column'
708  ],
709  'delete' => 'deleted_column'
710  ];
711  $GLOBALS['TSFE'] = new \stdClass();
712  $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
713  $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
714 
715  $connectionProphet = $this->prophesize(Connection::class);
716  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
717  $connectionProphet->getExpressionBuilder(Argument::cetera())->willReturn(
718  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
719  );
720  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
721  $queryBuilderProphet->expr()->willReturn(
722  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
723  );
724  $queryBuilderProphet->createNamedParameter(Argument::cetera())->willReturnArgument(0);
725 
726  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
727  $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
728  $connectionPoolProphet->getConnectionForTable(Argument::any($tableName, 'pages'))->willReturn($connectionProphet->reveal());
729  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
730  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
731 
733  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
734  ->setMethods(['dummy'])
735  ->disableOriginalConstructor()
736  ->getMock();
737  $mockQuerySettings->setIgnoreEnableFields(!$respectEnableFields);
738  $mockQuerySettings->setIncludeDeleted(!$respectEnableFields);
739 
741  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
742  ->setMethods(['isEnvironmentInFrontendMode'])
743  ->getMock();
744  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode === 'FE'));
745 
746  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
747  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
748  $actualSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
749  $this->assertSame($expectedSql, $actualSql);
750  unset($GLOBALS['TCA'][$tableName]);
751  }
752 
756  public function visibilityConstraintStatementGenerationThrowsExceptionIfTheQuerySettingsAreInconsistent()
757  {
758  $this->expectException(InconsistentQuerySettingsException::class);
759  $this->expectExceptionCode(1460975922);
760  $tableName = 'tx_foo_table';
761  $GLOBALS['TCA'][$tableName]['ctrl'] = [
762  'enablecolumns' => [
763  'disabled' => 'disabled_column'
764  ],
765  'delete' => 'deleted_column'
766  ];
767  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
768  ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
769  ->disableOriginalConstructor()
770  ->getMock();
771  $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue(false));
772  $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue([]));
773  $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue(true));
774 
776  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
777  ->setMethods(['isEnvironmentInFrontendMode'])
778  ->getMock();
779  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue(true));
780 
781  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
782  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
783  $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
784  unset($GLOBALS['TCA'][$tableName]);
785  }
786 
791  {
792  $table = $this->getUniqueId('tx_coretest_table');
793  return [
794  'set Pid to zero if rootLevel = 1' => [
795  '1',
796  $table,
797  $table . '.pid = 0'
798  ],
799  'set Pid to given Pids if rootLevel = 0' => [
800  '0',
801  $table,
802  $table . '.pid IN (42, 27)'
803  ],
804  'add 0 to given Pids if rootLevel = -1' => [
805  '-1',
806  $table,
807  $table . '.pid IN (42, 27, 0)'
808  ],
809  'set Pid to zero if rootLevel = -1 and no further pids given' => [
810  '-1',
811  $table,
812  $table . '.pid = 0',
813  []
814  ],
815  'set no statement for invalid configuration' => [
816  '2',
817  $table,
818  ''
819  ]
820  ];
821  }
822 
827  public function addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds = [42, 27])
828  {
829  $GLOBALS['TCA'][$table]['ctrl'] = [
830  'rootLevel' => $rootLevel
831  ];
832  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
833  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
834  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
835  $sql = $mockTypo3DbQueryParser->_callRef('getPageIdStatement', $table, $table, $storagePageIds);
836 
837  $this->assertSame($expectedSql, $sql);
838  }
839 }
static addInstance($className, $instance)
addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds=[42, 27])
static makeInstance($className,... $constructorArguments)
static resetSingletonInstances(array $newSingletonInstances)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']