11cd41be812883d0bf7865d056ffeb4ef38c8be7
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Persistence / Generic / Storage / Typo3DbQueryParserTest.php
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 use Prophecy\Argument;
17 use TYPO3\CMS\Core\Database\Connection;
18 use TYPO3\CMS\Core\Database\ConnectionPool;
19 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
20 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException;
23 use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedOrderException;
24
25 class Typo3DbQueryParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
26 {
27 /**
28 * @var array
29 */
30 protected $singletonInstances;
31
32 /**
33 * Set up tests
34 */
35 protected function setUp()
36 {
37 parent::setUp();
38 $this->singletonInstances = GeneralUtility::getSingletonInstances();
39 }
40
41 /**
42 * Clean up after tests
43 */
44 protected function tearDown()
45 {
46 GeneralUtility::purgeInstances();
47 GeneralUtility::resetSingletonInstances($this->singletonInstances);
48 parent::tearDown();
49 }
50
51 /**
52 * @return \Prophecy\Prophecy\ObjectProphecy
53 */
54 protected function getQueryBuilderWithExpressionBuilderProphet()
55 {
56 $connectionProphet = $this->prophesize(Connection::class);
57 $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
58 $querBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
59 $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
60 $querBuilderProphet->expr()->willReturn($expr);
61 return $querBuilderProphet;
62 }
63
64 /**
65 * @return \Prophecy\Prophecy\ObjectProphecy
66 */
67 protected function getQueryBuilderProphetWithQueryBuilderForSubselect()
68 {
69 $connectionProphet = $this->prophesize(Connection::class);
70 $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
71 $queryBuilderProphet = $this->prophesize(QueryBuilder::class, $connectionProphet->reveal());
72 $expr = GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal());
73 $queryBuilderProphet->expr()->willReturn(
74 $expr
75 );
76 $queryBuilderProphet->getConnection()->willReturn($connectionProphet->reveal());
77 $queryBuilderForSubselectMock = $this->getMockBuilder(QueryBuilder::class)
78 ->setMethods(['expr', 'unquoteSingleIdentifier'])
79 ->setConstructorArgs([$connectionProphet->reveal()])
80 ->getMock();
81 $connectionProphet->createQueryBuilder()->willReturn($queryBuilderForSubselectMock);
82 $queryBuilderForSubselectMock->expects($this->any())->method('expr')->will($this->returnValue($expr));
83 $queryBuilderForSubselectMock->expects($this->any())->method('unquoteSingleIdentifier')->will($this->returnCallback(function ($identifier) {
84 return $identifier;
85 }));
86 return $queryBuilderProphet;
87 }
88
89 /**
90 * @test
91 */
92 public function addSysLanguageStatementWorksForDefaultLanguage()
93 {
94 $table = $this->getUniqueId('tx_coretest_table');
95 $GLOBALS['TCA'][$table]['ctrl'] = [
96 'languageField' => 'sys_language_uid'
97 ];
98 /** @var \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings|\PHPUnit_Framework_MockObject_MockObject $querySettings */
99 $querySettings = $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class);
100 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
101 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
102 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
103 $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
104 $expectedSql = $table . '.sys_language_uid IN (0, -1)';
105 $this->assertSame($expectedSql, $sql);
106 }
107
108 /**
109 * @test
110 */
111 public function addSysLanguageStatementWorksForNonDefaultLanguage()
112 {
113 $table = $this->getUniqueId('tx_coretest_table');
114 $GLOBALS['TCA'][$table]['ctrl'] = [
115 'languageField' => 'sys_language_uid'
116 ];
117 /** @var \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings|\PHPUnit_Framework_MockObject_MockObject $querySettings */
118 $querySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
119 ->setMethods(['dummy'])
120 ->getMock();
121 $querySettings->setLanguageUid('1');
122 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
123 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
124 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
125 $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
126 $result = $table . '.sys_language_uid IN (1, -1)';
127 $this->assertSame($result, $sql);
128 }
129
130 /**
131 * @test
132 */
133 public function addSysLanguageStatementWorksInBackendContextWithNoGlobalTypoScriptFrontendControllerAvailable()
134 {
135 $table = $this->getUniqueId('tx_coretest_table');
136 $GLOBALS['TCA'][$table]['ctrl'] = [
137 'languageField' => 'sys_language_uid'
138 ];
139 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
140 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
141 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
142 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
143 $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
144 $expectedSql = $table . '.sys_language_uid IN (0, -1)';
145 $this->assertSame($expectedSql, $sql);
146 }
147
148 /**
149 * @test
150 */
151 public function addSysLanguageStatementWorksForDefaultLanguageWithoutDeleteStatementReturned()
152 {
153 $table = $this->getUniqueId('tx_coretest_table');
154 $GLOBALS['TCA'][$table]['ctrl'] = [
155 'languageField' => 'sys_language_uid',
156 'delete' => 'deleted'
157 ];
158 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
159 $querySettings->setLanguageUid(0);
160 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
161 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
162 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
163 $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
164 $expectedSql = $table . '.sys_language_uid IN (0, -1)';
165 $this->assertSame($expectedSql, $sql);
166 }
167
168 /**
169 * @test
170 */
171 public function addSysLanguageStatementWorksForForeignLanguageWithoutSubselection()
172 {
173 $table = $this->getUniqueId('tx_coretest_table');
174 $GLOBALS['TCA'][$table]['ctrl'] = [
175 'languageField' => 'sys_language_uid'
176 ];
177 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
178 $querySettings->setLanguageUid(2);
179 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
180 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
181 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
182 $sql = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
183 $expectedSql = $table . '.sys_language_uid IN (2, -1)';
184 $this->assertSame($expectedSql, $sql);
185 }
186
187 /**
188 * @test
189 */
190 public function addSysLanguageStatementWorksForForeignLanguageWithSubselectionWithoutDeleteStatementReturned()
191 {
192 $table = $this->getUniqueId('tx_coretest_table');
193 $GLOBALS['TCA'][$table]['ctrl'] = [
194 'languageField' => 'sys_language_uid',
195 'transOrigPointerField' => 'l10n_parent'
196 ];
197 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
198 $querySettings->setLanguageUid(2);
199 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
200
201 $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
202
203 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
204
205 $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
206 $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))))';
207 $this->assertSame($expectedSql, $compositeExpression->__toString());
208 }
209
210 /**
211 * @test
212 */
213 public function addSysLanguageStatementWorksForForeignLanguageWithSubselectionTakesDeleteStatementIntoAccountIfNecessary()
214 {
215 $table = $this->getUniqueId('tx_coretest_table');
216 $GLOBALS['TCA'][$table]['ctrl'] = [
217 'languageField' => 'sys_language_uid',
218 'transOrigPointerField' => 'l10n_parent',
219 'delete' => 'deleted'
220 ];
221 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
222 $querySettings->setLanguageUid(2);
223 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
224 $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
225 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
226 $compositeExpression= $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
227 $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
228 ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
229 'SELECT ' . $table . '.l10n_parent FROM ' . $table .
230 ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
231 $table . '.sys_language_uid = 2) AND (' .
232 $table . '.deleted = 0))))';
233 $this->assertSame($expectedSql, $compositeExpression->__toString());
234 }
235
236 /**
237 * @test
238 */
239 public function addSysLanguageStatementWorksInBackendContextWithSubselectionTakesDeleteStatementIntoAccountIfNecessary()
240 {
241 $table = 'tt_content';
242 $GLOBALS['TCA'][$table]['ctrl'] = [
243 'languageField' => 'sys_language_uid',
244 'transOrigPointerField' => 'l10n_parent',
245 'delete' => 'deleted'
246 ];
247 $querySettings = new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings();
248 $querySettings->setLanguageUid(2);
249 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
250
251 $queryBuilderProphet = $this->getQueryBuilderProphetWithQueryBuilderForSubselect();
252
253 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
254 $compositeExpression = $mockTypo3DbQueryParser->_callRef('getSysLanguageStatement', $table, $table, $querySettings);
255 $expectedSql = '(' . $table . '.sys_language_uid IN (2, -1))' .
256 ' OR ((' . $table . '.sys_language_uid = 0) AND (' . $table . '.uid NOT IN (' .
257 'SELECT ' . $table . '.l10n_parent FROM ' . $table .
258 ' WHERE (' . $table . '.l10n_parent > 0) AND (' .
259 $table . '.sys_language_uid = 2) AND (' .
260 $table . '.deleted = 0))))';
261 $this->assertSame($expectedSql, $compositeExpression->__toString());
262 }
263
264 /**
265 * @test
266 */
267 public function orderStatementGenerationWorks()
268 {
269 $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
270 ->setMethods(['getNodeTypeName'])
271 ->disableOriginalConstructor()
272 ->getMock();
273 $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('foo'));
274 $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
275 ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
276 ->disableOriginalConstructor()
277 ->getMock();
278 $mockDataMapper->expects($this->once())->method('convertClassNameToTableName')->with('foo')->will($this->returnValue('tx_myext_tablename'));
279 $mockDataMapper->expects($this->once())->method('convertPropertyNameToColumnName')->with('fooProperty', 'foo')->will($this->returnValue('converted_fieldname'));
280 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
281 $queryBuilderProphet->addOrderBy('tx_myext_tablename.converted_fieldname', 'ASC')->shouldBeCalledTimes(1);
282
283 $orderings = ['fooProperty' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING];
284 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
285 $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
286 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
287 $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
288 }
289
290 /**
291 * @test
292 */
293 public function orderStatementGenerationThrowsExceptionOnUnsupportedOrder()
294 {
295 $this->expectException(UnsupportedOrderException::class);
296 $this->expectExceptionCode(1242816074);
297 $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
298 ->setMethods(['getNodeTypeName'])
299 ->disableOriginalConstructor()
300 ->getMock();
301 $mockSource->expects($this->never())->method('getNodeTypeName');
302 $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
303 ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
304 ->disableOriginalConstructor()
305 ->getMock();
306 $mockDataMapper->expects($this->never())->method('convertClassNameToTableName');
307 $mockDataMapper->expects($this->never())->method('convertPropertyNameToColumnName');
308 $orderings = ['fooProperty' => 'unsupported_order'];
309 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
310 $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
311
312 $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
313 }
314
315 /**
316 * @test
317 */
318 public function orderStatementGenerationWorksWithMultipleOrderings()
319 {
320 $mockSource = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Selector::class)
321 ->setMethods(['getNodeTypeName'])
322 ->disableOriginalConstructor()
323 ->getMock();
324 $mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('Tx_MyExt_ClassName'));
325 $mockDataMapper = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class)
326 ->setMethods(['convertPropertyNameToColumnName', 'convertClassNameToTableName'])
327 ->disableOriginalConstructor()
328 ->getMock();
329 $mockDataMapper->expects($this->any())->method('convertClassNameToTableName')->with('Tx_MyExt_ClassName')->will($this->returnValue('tx_myext_tablename'));
330 $mockDataMapper->expects($this->any())->method('convertPropertyNameToColumnName')->will($this->returnValue('converted_fieldname'));
331 $orderings = [
332 'fooProperty' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
333 'barProperty' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
334 ];
335 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
336 $mockTypo3DbQueryParser->_set('dataMapper', $mockDataMapper);
337
338 $queryBuilder = $this->getMockBuilder(QueryBuilder::class)
339 ->disableOriginalConstructor()
340 ->setMethods(['addOrderBy'])
341 ->getMock();
342 $queryBuilder->expects($this->at(0))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'ASC');
343 $queryBuilder->expects($this->at(1))->method('addOrderBy')->with('tx_myext_tablename.converted_fieldname', 'DESC');
344
345 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilder);
346 $mockTypo3DbQueryParser->_callRef('parseOrderings', $orderings, $mockSource);
347 }
348
349 public function providerForVisibilityConstraintStatement()
350 {
351 return [
352 'in be: include all' => ['BE', true, [], true, ''],
353 'in be: ignore enable fields but do not include deleted' => ['BE', true, [], false, 'tx_foo_table.deleted_column = 0'],
354 'in be: respect enable fields but include deleted' => ['BE', false, [], true, 'tx_foo_table.disabled_column=0 AND (tx_foo_table.starttime_column<=123456789)'],
355 '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'],
356 'in fe: include all' => ['FE', true, [], true, ''],
357 'in fe: ignore enable fields but do not include deleted' => ['FE', true, [], false, 'tx_foo_table.deleted_column=0'],
358 '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)'],
359 '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)']
360 ];
361 }
362
363 /**
364 * @test
365 * @dataProvider providerForVisibilityConstraintStatement
366 */
367 public function visibilityConstraintStatementIsGeneratedAccordingToTheQuerySettings($mode, $ignoreEnableFields, $enableFieldsToBeIgnored, $deletedValue, $expectedSql)
368 {
369 $tableName = 'tx_foo_table';
370 $GLOBALS['TCA'][$tableName]['ctrl'] = [
371 'enablecolumns' => [
372 'disabled' => 'disabled_column',
373 'starttime' => 'starttime_column'
374 ],
375 'delete' => 'deleted_column'
376 ];
377 $GLOBALS['TSFE'] = new \stdClass();
378 $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
379 $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
380
381 $connectionProphet = $this->prophesize(Connection::class);
382 $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
383
384 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
385 $queryBuilderProphet->expr()->willReturn(
386 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
387 );
388
389 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
390 $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
391 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
392
393 $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
394 ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
395 ->disableOriginalConstructor()
396 ->getMock();
397 $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue($ignoreEnableFields));
398 $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue($enableFieldsToBeIgnored));
399 $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue($deletedValue));
400
401 /** @var $mockEnvironmentService \TYPO3\CMS\Extbase\Service\EnvironmentService | \PHPUnit_Framework_MockObject_MockObject */
402 $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
403 ->setMethods(['isEnvironmentInFrontendMode'])
404 ->getMock();
405 $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode == 'FE'));
406
407 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
408 $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
409 $resultSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
410 $this->assertSame($expectedSql, $resultSql);
411 unset($GLOBALS['TCA'][$tableName]);
412 }
413
414 public function providerForRespectEnableFields()
415 {
416 return [
417 'in be: respectEnableFields=false' => ['BE', false, ''],
418 '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'],
419 'in FE: respectEnableFields=false' => ['FE', false, ''],
420 '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)']
421 ];
422 }
423
424 /**
425 * @test
426 * @dataProvider providerForRespectEnableFields
427 */
428 public function respectEnableFieldsSettingGeneratesCorrectStatement($mode, $respectEnableFields, $expectedSql)
429 {
430 $tableName = 'tx_foo_table';
431 $GLOBALS['TCA'][$tableName]['ctrl'] = [
432 'enablecolumns' => [
433 'disabled' => 'disabled_column',
434 'starttime' => 'starttime_column'
435 ],
436 'delete' => 'deleted_column'
437 ];
438 $GLOBALS['TSFE'] = new \stdClass();
439 $GLOBALS['TSFE']->sys_page = new \TYPO3\CMS\Frontend\Page\PageRepository();
440 $GLOBALS['SIM_ACCESS_TIME'] = 123456789;
441
442 $connectionProphet = $this->prophesize(Connection::class);
443 $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
444
445 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
446 $queryBuilderProphet->expr()->willReturn(
447 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
448 );
449
450 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
451 $connectionPoolProphet->getQueryBuilderForTable(Argument::any($tableName, 'pages'))->willReturn($queryBuilderProphet->reveal());
452 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
453
454 /** @var \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings $mockQuerySettings */
455 $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
456 ->setMethods(['dummy'])
457 ->disableOriginalConstructor()
458 ->getMock();
459 $mockQuerySettings->setIgnoreEnableFields(!$respectEnableFields);
460 $mockQuerySettings->setIncludeDeleted(!$respectEnableFields);
461
462 /** @var $mockEnvironmentService \TYPO3\CMS\Extbase\Service\EnvironmentService | \PHPUnit_Framework_MockObject_MockObject */
463 $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
464 ->setMethods(['isEnvironmentInFrontendMode'])
465 ->getMock();
466 $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue($mode == 'FE'));
467
468 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
469 $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
470 $actualSql = $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
471 $this->assertSame($expectedSql, $actualSql);
472 unset($GLOBALS['TCA'][$tableName]);
473 }
474
475 /**
476 * @test
477 */
478 public function visibilityConstraintStatementGenerationThrowsExceptionIfTheQuerySettingsAreInconsistent()
479 {
480 $this->expectException(InconsistentQuerySettingsException::class);
481 $this->expectExceptionCode(1460975922);
482 $tableName = 'tx_foo_table';
483 $GLOBALS['TCA'][$tableName]['ctrl'] = [
484 'enablecolumns' => [
485 'disabled' => 'disabled_column'
486 ],
487 'delete' => 'deleted_column'
488 ];
489 $mockQuerySettings = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class)
490 ->setMethods(['getIgnoreEnableFields', 'getEnableFieldsToBeIgnored', 'getIncludeDeleted'])
491 ->disableOriginalConstructor()
492 ->getMock();
493 $mockQuerySettings->expects($this->once())->method('getIgnoreEnableFields')->will($this->returnValue(false));
494 $mockQuerySettings->expects($this->once())->method('getEnableFieldsToBeIgnored')->will($this->returnValue([]));
495 $mockQuerySettings->expects($this->once())->method('getIncludeDeleted')->will($this->returnValue(true));
496
497 /** @var $mockEnvironmentService \TYPO3\CMS\Extbase\Service\EnvironmentService | \PHPUnit_Framework_MockObject_MockObject */
498 $mockEnvironmentService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Service\EnvironmentService::class)
499 ->setMethods(['isEnvironmentInFrontendMode'])
500 ->getMock();
501 $mockEnvironmentService->expects($this->any())->method('isEnvironmentInFrontendMode')->will($this->returnValue(true));
502
503 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
504 $mockTypo3DbQueryParser->_set('environmentService', $mockEnvironmentService);
505 $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
506 unset($GLOBALS['TCA'][$tableName]);
507 }
508
509 /**
510 * DataProvider for addPageIdStatement Tests
511 */
512 public function providerForAddPageIdStatementData()
513 {
514 $table = $this->getUniqueId('tx_coretest_table');
515 return [
516 'set Pid to zero if rootLevel = 1' => [
517 '1',
518 $table,
519 $table . '.pid = 0'
520 ],
521 'set Pid to given Pids if rootLevel = 0' => [
522 '0',
523 $table,
524 $table . '.pid IN (42, 27)'
525 ],
526 'add 0 to given Pids if rootLevel = -1' => [
527 '-1',
528 $table,
529 $table . '.pid IN (42, 27, 0)'
530 ],
531 'set Pid to zero if rootLevel = -1 and no further pids given' => [
532 '-1',
533 $table,
534 $table . '.pid = 0',
535 []
536 ],
537 'set no statement for invalid configuration' => [
538 '2',
539 $table,
540 ''
541 ]
542 ];
543 }
544
545 /**
546 * @test
547 * @dataProvider providerForAddPageIdStatementData
548 */
549 public function addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds = [42, 27])
550 {
551 $GLOBALS['TCA'][$table]['ctrl'] = [
552 'rootLevel' => $rootLevel
553 ];
554 $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, ['dummy'], [], '', false);
555 $queryBuilderProphet = $this->getQueryBuilderWithExpressionBuilderProphet();
556 $mockTypo3DbQueryParser->_set('queryBuilder', $queryBuilderProphet->reveal());
557 $sql = $mockTypo3DbQueryParser->_callRef('getPageIdStatement', $table, $table, $storagePageIds);
558
559 $this->assertSame($expectedSql, $sql);
560 }
561 }