TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
Typo3DbQueryParserTest.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Persistence\Generic\Storage;
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 
17 use Prophecy\Argument;
35 
37 {
42 
46  protected function setUp()
47  {
48  parent::setUp();
49  $this->singletonInstances = GeneralUtility::getSingletonInstances();
50  }
51 
55  protected function tearDown()
56  {
58  GeneralUtility::resetSingletonInstances($this->singletonInstances);
59  parent::tearDown();
60  }
61 
66  {
67  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
68  $subject = $this->getAccessibleMock(
69  Typo3DbQueryParser::class,
70  // Shut down some methods not important for this test
71  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints']
72  );
73  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
74  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
75 
76  $queryProphecy = $this->prophesize(QueryInterface::class);
77  $sourceProphecy = $this->prophesize(SourceInterface::class);
78  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
79  $queryProphecy->getOrderings()->willReturn([]);
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 
107  // Test part: getConstraint returns not implemented object
108  $constraintProphecy = $this->prophesize(ConstraintInterface::class);
109  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
110 
111  $this->expectException(\RuntimeException::class);
112  $this->expectExceptionCode(1476199898);
113  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
114  }
115 
120  {
121  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
122  $subject = $this->getAccessibleMock(
123  Typo3DbQueryParser::class,
124  // Shut down some methods not important for this test
125  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
126  );
127  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
128  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
129 
130  $queryProphecy = $this->prophesize(QueryInterface::class);
131  $sourceProphecy = $this->prophesize(SourceInterface::class);
132  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
133  $queryProphecy->getOrderings()->willReturn([]);
134 
135  // Test part: getConstraint returns simple constraint, and should push to andWhere()
136  $constraintProphecy = $this->prophesize(ComparisonInterface::class);
137  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
138  $subject->expects($this->once())->method('parseComparison')->willReturn('heinz');
139  $queryBuilderProphecy->andWhere('heinz')->shouldBeCalled();
140 
141  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
142  }
143 
148  {
149  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
150  $subject = $this->getAccessibleMock(
151  Typo3DbQueryParser::class,
152  // Shut down some methods not important for this test
153  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
154  );
155  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
156  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
157 
158  $queryProphecy = $this->prophesize(QueryInterface::class);
159  $sourceProphecy = $this->prophesize(SourceInterface::class);
160  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
161  $queryProphecy->getOrderings()->willReturn([]);
162 
163  $constraintProphecy = $this->prophesize(NotInterface::class);
164  $subConstraintProphecy = $this->prophesize(ComparisonInterface::class);
165  $constraintProphecy->getConstraint()->shouldBeCalled()->willReturn($subConstraintProphecy->reveal());
166  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
167  $subject->expects($this->once())->method('parseComparison')->willReturn('heinz');
168  $queryBuilderProphecy->andWhere(' NOT(heinz)')->shouldBeCalled();
169 
170  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
171  }
172 
177  {
178  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
179  $subject = $this->getAccessibleMock(
180  Typo3DbQueryParser::class,
181  // Shut down some methods not important for this test
182  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
183  );
184  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
185  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
186 
187  $queryProphecy = $this->prophesize(QueryInterface::class);
188  $sourceProphecy = $this->prophesize(SourceInterface::class);
189  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
190  $queryProphecy->getOrderings()->willReturn([]);
191 
192  $constraintProphecy = $this->prophesize(AndInterface::class);
193  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
194  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
195  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
196  $constraint2Prophecy = $this->prophesize(ComparisonInterface::class);
197  $constraintProphecy->getConstraint2()->willReturn($constraint2Prophecy->reveal());
198  $subject->expects($this->any())->method('parseComparison')->willReturn('heinz');
199  $expressionProphecy = $this->prophesize(ExpressionBuilder::class);
200  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionProphecy->reveal());
201  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
202  $compositeExpressionProphecy->__toString()->willReturn('heinz AND heinz');
203  $compositeExpressionRevelation = $compositeExpressionProphecy->reveal();
204  $expressionProphecy->andX('heinz', 'heinz')->shouldBeCalled()->willReturn($compositeExpressionRevelation);
205  $queryBuilderProphecy->andWhere($compositeExpressionRevelation)->shouldBeCalled();
206 
207  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
208  }
209 
214  {
215  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
216  $subject = $this->getAccessibleMock(
217  Typo3DbQueryParser::class,
218  // Shut down some methods not important for this test
219  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
220  );
221  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
222  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
223 
224  $queryProphecy = $this->prophesize(QueryInterface::class);
225  $sourceProphecy = $this->prophesize(SourceInterface::class);
226  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
227  $queryProphecy->getOrderings()->willReturn([]);
228 
229  $constraintProphecy = $this->prophesize(AndInterface::class);
230  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
231  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
232  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
233  // no result for constraint2
234  $constraintProphecy->getConstraint2()->willReturn(null);
235 
236  // not be called
237  $queryBuilderProphecy->andWhere()->shouldNotBeCalled();
238 
239  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
240  }
241 
246  {
247  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
248  $subject = $this->getAccessibleMock(
249  Typo3DbQueryParser::class,
250  // Shut down some methods not important for this test
251  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
252  );
253  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
254  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
255 
256  $queryProphecy = $this->prophesize(QueryInterface::class);
257  $sourceProphecy = $this->prophesize(SourceInterface::class);
258  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
259  $queryProphecy->getOrderings()->willReturn([]);
260 
261  $constraintProphecy = $this->prophesize(OrInterface::class);
262  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
263  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
264  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
265  $constraint2Prophecy = $this->prophesize(ComparisonInterface::class);
266  $constraintProphecy->getConstraint2()->willReturn($constraint2Prophecy->reveal());
267  $subject->expects($this->any())->method('parseComparison')->willReturn('heinz');
268  $expressionProphecy = $this->prophesize(ExpressionBuilder::class);
269  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionProphecy->reveal());
270  $compositeExpressionProphecy = $this->prophesize(CompositeExpression::class);
271  $compositeExpressionProphecy->__toString()->willReturn('heinz OR heinz');
272  $compositeExpressionRevelation = $compositeExpressionProphecy->reveal();
273  $expressionProphecy->orX('heinz', 'heinz')->shouldBeCalled()->willReturn($compositeExpressionRevelation);
274  $queryBuilderProphecy->andWhere($compositeExpressionRevelation)->shouldBeCalled();
275 
276  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
277  }
278 
283  {
284  // Prepare subject, turn off initialize qb method and inject qb prophecy revelation
285  $subject = $this->getAccessibleMock(
286  Typo3DbQueryParser::class,
287  // Shut down some methods not important for this test
288  ['initializeQueryBuilder', 'parseOrderings', 'addTypo3Constraints', 'parseComparison']
289  );
290  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
291  $subject->_set('queryBuilder', $queryBuilderProphecy->reveal());
292 
293  $queryProphecy = $this->prophesize(QueryInterface::class);
294  $sourceProphecy = $this->prophesize(SourceInterface::class);
295  $queryProphecy->getSource()->willReturn($sourceProphecy->reveal());
296  $queryProphecy->getOrderings()->willReturn([]);
297 
298  $constraintProphecy = $this->prophesize(OrInterface::class);
299  $queryProphecy->getConstraint()->willReturn($constraintProphecy->reveal());
300  $constraint1Prophecy = $this->prophesize(ComparisonInterface::class);
301  $constraintProphecy->getConstraint1()->willReturn($constraint1Prophecy->reveal());
302  // no result for constraint2
303  $constraintProphecy->getConstraint2()->willReturn(null);
304 
305  // not be called
306  $queryBuilderProphecy->andWhere()->shouldNotBeCalled();
307 
308  $subject->convertQueryToDoctrineQueryBuilder($queryProphecy->reveal());
309  }
310 
315  {
316  $connectionProphet = $this->prophesize(Connection::class);
317  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
318  $querBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
319  $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
320  $querBuilderProphet->expr()->willReturn($expr);
321  return $querBuilderProphet;
322  }
323 
328  {
329  $connectionProphet = $this->prophesize(Connection::class);
330  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
331  $queryBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
332  $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
333  $queryBuilderProphet->expr()->willReturn(
334  $expr
335  );
336  $queryBuilderProphet->getConnection()->willReturn($connectionProphet->reveal());
337  $queryBuilderForSubselectMock = $this->getMockBuilder(QueryBuilder::class)
338  ->setMethods(['expr', 'unquoteSingleIdentifier'])
339  ->setConstructorArgs([$connectionProphet->reveal()])
340  ->getMock();
341  $connectionProphet->createQueryBuilder()->willReturn($queryBuilderForSubselectMock);
342  $queryBuilderForSubselectMock->expects($this->any())->method('expr')->will($this->returnValue($expr));
343  $queryBuilderForSubselectMock->expects($this->any())->method('unquoteSingleIdentifier')->will($this->returnCallback(function ($identifier) {
344  return $identifier;
345  }));
346  return $queryBuilderProphet;
347  }
348 
352  public function addSysLanguageStatementWorksForDefaultLanguage()
353  {
354  $table = $this->getUniqueId('tx_coretest_table');
355  $GLOBALS['TCA'][$table]['ctrl'] = [
356  'languageField' => 'sys_language_uid'
357  ];
359  $querySettings = $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class);
360  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
361  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
362  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
363  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
364  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
365  $this->assertSame($expectedSql, $sql);
366  }
367 
371  public function addSysLanguageStatementWorksForNonDefaultLanguage()
372  {
373  $table = $this->getUniqueId('tx_coretest_table');
374  $GLOBALS['TCA'][$table]['ctrl'] = [
375  'languageField' => 'sys_language_uid'
376  ];
378  $querySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
379  ->setMethods(['dummy'])
380  ->getMock();
381  $querySettings->setLanguageUid('1');
382  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
383  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
384  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
385  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
386  $result = $table . '.sys_language_uid IN (1, -1)';
387  $this->assertSame($result, $sql);
388  }
389 
394  {
395  $table = $this->getUniqueId('tx_coretest_table');
396  $GLOBALS['TCA'][$table]['ctrl'] = [
397  'languageField' => 'sys_language_uid'
398  ];
399  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
400  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
401  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
402  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
403  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
404  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
405  $this->assertSame($expectedSql, $sql);
406  }
407 
412  {
413  $table = $this->getUniqueId('tx_coretest_table');
414  $GLOBALS['TCA'][$table]['ctrl'] = [
415  'languageField' => 'sys_language_uid',
416  'delete' => 'deleted'
417  ];
418  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
419  $querySettings->setLanguageUid(0);
420  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
421  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
422  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
423  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
424  $expectedSql = $table . '.sys_language_uid IN (0, -1)';
425  $this->assertSame($expectedSql, $sql);
426  }
427 
432  {
433  $table = $this->getUniqueId('tx_coretest_table');
434  $GLOBALS['TCA'][$table]['ctrl'] = [
435  'languageField' => 'sys_language_uid'
436  ];
437  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
438  $querySettings->setLanguageUid(2);
439  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
440  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
441  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
442  $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
443  $expectedSql = $table . '.sys_language_uid IN (2, -1)';
444  $this->assertSame($expectedSql, $sql);
445  }
446 
451  {
452  $table = $this->getUniqueId('tx_coretest_table');
453  $GLOBALS['TCA'][$table]['ctrl'] = [
454  'languageField' => 'sys_language_uid',
455  'transOrigPointerField' => 'l10n_parent'
456  ];
457  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
458  $querySettings->setLanguageUid(2);
459  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
460 
461  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
462 
463  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
464 
465  $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
466  $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))))';
467  $this->assertSame($expectedSql, $compositeExpression->__toString());
468  }
469 
474  {
475  $table = $this->getUniqueId('tx_coretest_table');
476  $GLOBALS['TCA'][$table]['ctrl'] = [
477  'languageField' => 'sys_language_uid',
478  'transOrigPointerField' => 'l10n_parent',
479  'delete' => 'deleted'
480  ];
481  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
482  $querySettings->setLanguageUid(2);
483  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
484  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
485  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
486  $compositeExpression= $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
487  $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
488  ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
489  'SELECT ' . $table . '.l10n_parent FROM ' . $table .
490  ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
491  $table . '.sys_language_uid = 2) AND (' .
492  $table . '.deleted = 0))))';
493  $this->assertSame($expectedSql, $compositeExpression->__toString());
494  }
495 
500  {
501  $table = 'tt_content';
502  $GLOBALS['TCA'][$table]['ctrl'] = [
503  'languageField' => 'sys_language_uid',
504  'transOrigPointerField' => 'l10n_parent',
505  'delete' => 'deleted'
506  ];
507  $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
508  $querySettings->setLanguageUid(2);
509  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
510 
511  $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
512 
513  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
514  $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
515  $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
516  ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
517  'SELECT ' . $table . '.l10n_parent FROM ' . $table .
518  ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
519  $table . '.sys_language_uid = 2) AND (' .
520  $table . '.deleted = 0))))';
521  $this->assertSame($expectedSql, $compositeExpression->__toString());
522  }
523 
528  {
529  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
530  ->setMethods(['getNodeTypeName'])
531  ->disableOriginalConstructor()
532  ->getMock();
533  $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('foo'));
534  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
535  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
536  ->disableOriginalConstructor()
537  ->getMock();
538  $mockDataMapper->expects($this->once())->method('convertClassNameToTableName')->with('foo')->will($this->returnValue('tx_myext_tablename'));
539  $mockDataMapper->expects($this->once())->method('convertPropertyNameToColumnName')->with('fooProperty', 'foo')->will($this->returnValue('converted_fieldname'));
540  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
541  $queryBuilderProphet->addOrderBy('tx_myext_tablename.converted_fieldname', 'ASC')->shouldBeCalledTimes(1);
542 
543  $orderings = ['fooProperty' => QueryInterface::ORDER_ASCENDING];
544  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
545  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
546  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
547  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
548  }
549 
554  {
555  $this->expectException(UnsupportedOrderException::class);
556  $this->expectExceptionCode(1242816074);
557  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
558  ->setMethods(['getNodeTypeName'])
559  ->disableOriginalConstructor()
560  ->getMock();
561  $mockSource->expects($this->never())->method('getNodeTypeName');
562  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
563  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
564  ->disableOriginalConstructor()
565  ->getMock();
566  $mockDataMapper->expects($this->never())->method('convertClassNameToTableName');
567  $mockDataMapper->expects($this->never())->method('convertPropertyNameToColumnName');
568  $orderings = ['fooProperty' => 'unsupported_order'];
569  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
570  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
571 
572  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
573  }
574 
579  {
580  $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
581  ->setMethods(['getNodeTypeName'])
582  ->disableOriginalConstructor()
583  ->getMock();
584  $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('Tx_MyExt_ClassName'));
585  $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
586  ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
587  ->disableOriginalConstructor()
588  ->getMock();
589  $mockDataMapper->expects($this->any())->method('convertClassNameToTableName')->with('Tx_MyExt_ClassName')->will($this->returnValue('tx_myext_tablename'));
590  $mockDataMapper->expects($this->any())->method('convertPropertyNameToColumnName')->will($this->returnValue('converted_fieldname'));
591  $orderings = [
592  'fooProperty' => QueryInterface::ORDER_ASCENDING,
593  'barProperty' => QueryInterface::ORDER_DESCENDING
594  ];
595  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
596  $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
597 
598  $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
599  ->disableOriginalConstructor()
600  ->setMethods(['addOrderBy'])
601  ->getMock();
602  $queryBuilder->expects($this->at(0))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'ASC');
603  $queryBuilder->expects($this->at(1))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'DESC');
604 
605  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilder);
606  $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
607  }
608 
610  {
611  return [
612  'in be: include all' => ['BE', true, [], true, ''],
613  'in be: ignore enable fields but do not include deleted' => ['BE', true, [], false, 'tx_foo_table.deleted_column = 0'],
614  'in be: respect enable fields but include deleted' => ['BE', false, [], true, 'tx_foo_table.disabled_column=0 AND (tx_foo_table.starttime_column<=123456789)'],
615  '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'],
616  'in fe: include all' => ['FE', true, [], true, ''],
617  'in fe: ignore enable fields but do not include deleted' => ['FE', true, [], false, 'tx_foo_table.deleted_column=0'],
618  '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)'],
619  '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)']
620  ];
621  }
622 
627  public function visibilityConstraintStatementIsGeneratedAccordingToTheQuerySettings($mode, $ignoreEnableFields, $enableFieldsToBeIgnored, $deletedValue, $expectedSql)
628  {
629  $tableName = 'tx_foo_table';
630  $GLOBALS['TCA'][$tableName]['ctrl'] = [
631  'enablecolumns' => [
632  'disabled' => 'disabled_column',
633  'starttime' => 'starttime_column'
634  ],
635  'delete' => 'deleted_column'
636  ];
637  $GLOBALS['TSFE'] = new \stdClass();
638  $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
639  $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
640 
641  $connectionProphet = $this->prophesize(Connection::class);
642  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
643 
644  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
645  $queryBuilderProphet->expr()->willReturn(
646  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
647  );
648  $queryBuilderProphet->createNamedParameter(Argument::cetera())->willReturnArgument(0);
649 
650  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
651  $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
652  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
653 
654  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
655  ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
656  ->disableOriginalConstructor()
657  ->getMock();
658  $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue($ignoreEnableFields));
659  $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue($enableFieldsToBeIgnored));
660  $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue($deletedValue));
661 
663  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
664  ->setMethods(['isEnvironmentInFrontendMode'])
665  ->getMock();
666  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode == 'FE'));
667 
668  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
669  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
670  $resultSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
671  $this->assertSame($expectedSql, $resultSql);
672  unset($GLOBALS['TCA'][$tableName]);
673  }
674 
676  {
677  return [
678  'in be: respectEnableFields=false' => ['BE', false, ''],
679  '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'],
680  'in FE: respectEnableFields=false' => ['FE', false, ''],
681  '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)']
682  ];
683  }
684 
689  public function respectEnableFieldsSettingGeneratesCorrectStatement($mode, $respectEnableFields, $expectedSql)
690  {
691  $tableName = 'tx_foo_table';
692  $GLOBALS['TCA'][$tableName]['ctrl'] = [
693  'enablecolumns' => [
694  'disabled' => 'disabled_column',
695  'starttime' => 'starttime_column'
696  ],
697  'delete' => 'deleted_column'
698  ];
699  $GLOBALS['TSFE'] = new \stdClass();
700  $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
701  $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
702 
703  $connectionProphet = $this->prophesize(Connection::class);
704  $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
705 
706  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
707  $queryBuilderProphet->expr()->willReturn(
708  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
709  );
710  $queryBuilderProphet->createNamedParameter(Argument::cetera())->willReturnArgument(0);
711 
712  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
713  $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
714  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
715 
717  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
718  ->setMethods(['dummy'])
719  ->disableOriginalConstructor()
720  ->getMock();
721  $mockQuerySettings->setIgnoreEnableFields(!$respectEnableFields);
722  $mockQuerySettings->setIncludeDeleted(!$respectEnableFields);
723 
725  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
726  ->setMethods(['isEnvironmentInFrontendMode'])
727  ->getMock();
728  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode == 'FE'));
729 
730  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
731  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
732  $actualSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
733  $this->assertSame($expectedSql, $actualSql);
734  unset($GLOBALS['TCA'][$tableName]);
735  }
736 
740  public function visibilityConstraintStatementGenerationThrowsExceptionIfTheQuerySettingsAreInconsistent()
741  {
742  $this->expectException(InconsistentQuerySettingsException::class);
743  $this->expectExceptionCode(1460975922);
744  $tableName = 'tx_foo_table';
745  $GLOBALS['TCA'][$tableName]['ctrl'] = [
746  'enablecolumns' => [
747  'disabled' => 'disabled_column'
748  ],
749  'delete' => 'deleted_column'
750  ];
751  $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
752  ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
753  ->disableOriginalConstructor()
754  ->getMock();
755  $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue(false));
756  $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue([]));
757  $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue(true));
758 
760  $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
761  ->setMethods(['isEnvironmentInFrontendMode'])
762  ->getMock();
763  $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue(true));
764 
765  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
766  $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
767  $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
768  unset($GLOBALS['TCA'][$tableName]);
769  }
770 
775  {
776  $table = $this->getUniqueId('tx_coretest_table');
777  return [
778  'set Pid to zero if rootLevel = 1' => [
779  '1',
780  $table,
781  $table . '.pid = 0'
782  ],
783  'set Pid to given Pids if rootLevel = 0' => [
784  '0',
785  $table,
786  $table . '.pid IN (42, 27)'
787  ],
788  'add 0 to given Pids if rootLevel = -1' => [
789  '-1',
790  $table,
791  $table . '.pid IN (42, 27, 0)'
792  ],
793  'set Pid to zero if rootLevel = -1 and no further pids given' => [
794  '-1',
795  $table,
796  $table . '.pid = 0',
797  []
798  ],
799  'set no statement for invalid configuration' => [
800  '2',
801  $table,
802  ''
803  ]
804  ];
805  }
806 
811  public function addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds = [42, 27])
812  {
813  $GLOBALS['TCA'][$table]['ctrl'] = [
814  'rootLevel' => $rootLevel
815  ];
816  $mockTypo3DbQueryParser = $this->getAccessibleMock(Typo3DbQueryParser::class, ['dummy'], [], '', false);
817  $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
818  $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
819  $sql = $mockTypo3DbQueryParser->_callRef('getPageIdStatement', $table, $table, $storagePageIds);
820 
821  $this->assertSame($expectedSql, $sql);
822  }
823 }
addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds=[42, 27])
static resetSingletonInstances(array $newSingletonInstances)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
getAccessibleMock($originalClassName, $methods=[], array $arguments=[], $mockClassName= '', $callOriginalConstructor=true, $callOriginalClone=true, $callAutoload=true)
static addInstance($className, $instance)