c47ec9f330f9bb19c06fc0bd7cc222a2cd2f5f5e
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / Page / PageRepositoryTest.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Tests\Functional\Page;
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;
18 use TYPO3\CMS\Core\Context\Context;
19 use TYPO3\CMS\Core\Context\LanguageAspect;
20 use TYPO3\CMS\Core\Context\WorkspaceAspect;
21 use TYPO3\CMS\Core\Database\ConnectionPool;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Frontend\Page\PageRepository;
24 use TYPO3\CMS\Frontend\Page\PageRepositoryGetPageHookInterface;
25
26 /**
27 * Test case
28 */
29 class PageRepositoryTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
30 {
31 protected $coreExtensionsToLoad = ['frontend'];
32
33 protected function setUp()
34 {
35 parent::setUp();
36 $this->importDataSet(__DIR__ . '/../Fixtures/pages.xml');
37 }
38
39 /**
40 * @test
41 */
42 public function getMenuSingleUidRoot()
43 {
44 $subject = new PageRepository();
45 $rows = $subject->getMenu(1, 'uid, title');
46 $this->assertArrayHasKey(2, $rows);
47 $this->assertArrayHasKey(3, $rows);
48 $this->assertArrayHasKey(4, $rows);
49 $this->assertCount(3, $rows);
50 }
51
52 /**
53 * @test
54 */
55 public function getMenuSingleUidSubpage()
56 {
57 $subject = new PageRepository();
58 $rows = $subject->getMenu(2, 'uid, title');
59 $this->assertArrayHasKey(5, $rows);
60 $this->assertArrayHasKey(6, $rows);
61 $this->assertArrayHasKey(7, $rows);
62 $this->assertCount(3, $rows);
63 }
64
65 /**
66 * @test
67 */
68 public function getMenuMultipleUid()
69 {
70 $subject = new PageRepository();
71 $rows = $subject->getMenu([2, 3], 'uid, title');
72 $this->assertArrayHasKey(5, $rows);
73 $this->assertArrayHasKey(6, $rows);
74 $this->assertArrayHasKey(7, $rows);
75 $this->assertArrayHasKey(8, $rows);
76 $this->assertArrayHasKey(9, $rows);
77 $this->assertCount(5, $rows);
78 }
79
80 /**
81 * @test
82 */
83 public function getMenuPageOverlay()
84 {
85 $subject = new PageRepository(new Context([
86 'language' => new LanguageAspect(1)
87 ]));
88
89 $rows = $subject->getMenu([2, 3], 'uid, title');
90 $this->assertEquals('Attrappe 1-2-5', $rows[5]['title']);
91 $this->assertEquals('Attrappe 1-2-6', $rows[6]['title']);
92 $this->assertEquals('Dummy 1-2-7', $rows[7]['title']);
93 $this->assertEquals('Dummy 1-3-8', $rows[8]['title']);
94 $this->assertEquals('Attrappe 1-3-9', $rows[9]['title']);
95 $this->assertCount(5, $rows);
96 }
97
98 /**
99 * @test
100 */
101 public function getPageOverlayById()
102 {
103 $subject = new PageRepository();
104 $row = $subject->getPageOverlay(1, 1);
105 $this->assertOverlayRow($row);
106 $this->assertEquals('Wurzel 1', $row['title']);
107 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
108 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
109 }
110
111 /**
112 * @test
113 */
114 public function getPageOverlayByIdWithoutTranslation()
115 {
116 $subject = new PageRepository();
117 $row = $subject->getPageOverlay(4, 1);
118 $this->assertInternalType('array', $row);
119 $this->assertCount(0, $row);
120 }
121
122 /**
123 * @test
124 */
125 public function getPageOverlayByRow()
126 {
127 $subject = new PageRepository();
128 $orig = $subject->getPage(1);
129 $row = $subject->getPageOverlay($orig, 1);
130 $this->assertOverlayRow($row);
131 $this->assertEquals(1, $row['uid']);
132 $this->assertEquals('Wurzel 1', $row['title']);
133 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
134 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
135 }
136
137 /**
138 * @test
139 */
140 public function getPageOverlayByRowWithoutTranslation()
141 {
142 $subject = new PageRepository();
143 $orig = $subject->getPage(4);
144 $row = $subject->getPageOverlay($orig, 1);
145 $this->assertInternalType('array', $row);
146 $this->assertEquals(4, $row['uid']);
147 $this->assertEquals('Dummy 1-4', $row['title']);//original title
148 }
149
150 /**
151 * @test
152 */
153 public function getPagesOverlayByIdSingle()
154 {
155 $subject = new PageRepository(new Context([
156 'language' => new LanguageAspect(1)
157 ]));
158 $rows = $subject->getPagesOverlay([1]);
159 $this->assertInternalType('array', $rows);
160 $this->assertCount(1, $rows);
161 $this->assertArrayHasKey(0, $rows);
162
163 $row = $rows[0];
164 $this->assertOverlayRow($row);
165 $this->assertEquals('Wurzel 1', $row['title']);
166 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
167 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
168 }
169
170 /**
171 * @test
172 */
173 public function getPagesOverlayByIdMultiple()
174 {
175 $subject = new PageRepository(new Context([
176 'language' => new LanguageAspect(1)
177 ]));
178 $rows = $subject->getPagesOverlay([1, 5]);
179 $this->assertInternalType('array', $rows);
180 $this->assertCount(2, $rows);
181 $this->assertArrayHasKey(0, $rows);
182 $this->assertArrayHasKey(1, $rows);
183
184 $row = $rows[0];
185 $this->assertOverlayRow($row);
186 $this->assertEquals('Wurzel 1', $row['title']);
187 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
188 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
189
190 $row = $rows[1];
191 $this->assertOverlayRow($row);
192 $this->assertEquals('Attrappe 1-2-5', $row['title']);
193 $this->assertEquals('904', $row['_PAGES_OVERLAY_UID']);
194 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
195 }
196
197 /**
198 * @test
199 */
200 public function getPagesOverlayByIdMultipleSomeNotOverlaid()
201 {
202 $subject = new PageRepository(new Context([
203 'language' => new LanguageAspect(1)
204 ]));
205 $rows = $subject->getPagesOverlay([1, 4, 5, 8]);
206 $this->assertInternalType('array', $rows);
207 $this->assertCount(2, $rows);
208 $this->assertArrayHasKey(0, $rows);
209 $this->assertArrayHasKey(2, $rows);
210
211 $row = $rows[0];
212 $this->assertOverlayRow($row);
213 $this->assertEquals('Wurzel 1', $row['title']);
214
215 $row = $rows[2];
216 $this->assertOverlayRow($row);
217 $this->assertEquals('Attrappe 1-2-5', $row['title']);
218 }
219
220 /**
221 * @test
222 */
223 public function getPagesOverlayByRowSingle()
224 {
225 $subject = new PageRepository();
226 $origRow = $subject->getPage(1);
227
228 $subject = new PageRepository(new Context([
229 'language' => new LanguageAspect(1)
230 ]));
231 $rows = $subject->getPagesOverlay([$origRow]);
232 $this->assertInternalType('array', $rows);
233 $this->assertCount(1, $rows);
234 $this->assertArrayHasKey(0, $rows);
235
236 $row = $rows[0];
237 $this->assertOverlayRow($row);
238 $this->assertEquals('Wurzel 1', $row['title']);
239 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
240 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
241 }
242
243 /**
244 * @test
245 */
246 public function getPagesOverlayByRowMultiple()
247 {
248 $subject = new PageRepository();
249 $orig1 = $subject->getPage(1);
250 $orig2 = $subject->getPage(5);
251
252 $subject = new PageRepository(new Context([
253 'language' => new LanguageAspect(1)
254 ]));
255 $rows = $subject->getPagesOverlay([1 => $orig1, 5 => $orig2]);
256 $this->assertInternalType('array', $rows);
257 $this->assertCount(2, $rows);
258 $this->assertArrayHasKey(1, $rows);
259 $this->assertArrayHasKey(5, $rows);
260
261 $row = $rows[1];
262 $this->assertOverlayRow($row);
263 $this->assertEquals('Wurzel 1', $row['title']);
264 $this->assertEquals('901', $row['_PAGES_OVERLAY_UID']);
265 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
266
267 $row = $rows[5];
268 $this->assertOverlayRow($row);
269 $this->assertEquals('Attrappe 1-2-5', $row['title']);
270 $this->assertEquals('904', $row['_PAGES_OVERLAY_UID']);
271 $this->assertEquals(1, $row['_PAGES_OVERLAY_LANGUAGE']);
272 }
273
274 /**
275 * @test
276 */
277 public function getPagesOverlayByRowMultipleSomeNotOverlaid()
278 {
279 $subject = new PageRepository();
280 $orig1 = $subject->getPage(1);
281 $orig2 = $subject->getPage(7);
282 $orig3 = $subject->getPage(9);
283
284 $subject = new PageRepository(new Context([
285 'language' => new LanguageAspect(1)
286 ]));
287 $rows = $subject->getPagesOverlay([$orig1, $orig2, $orig3]);
288 $this->assertInternalType('array', $rows);
289 $this->assertCount(3, $rows);
290 $this->assertArrayHasKey(0, $rows);
291 $this->assertArrayHasKey(1, $rows);
292 $this->assertArrayHasKey(2, $rows);
293
294 $row = $rows[0];
295 $this->assertOverlayRow($row);
296 $this->assertEquals('Wurzel 1', $row['title']);
297
298 $row = $rows[1];
299 $this->assertNotOverlayRow($row);
300 $this->assertEquals('Dummy 1-2-7', $row['title']);
301
302 $row = $rows[2];
303 $this->assertOverlayRow($row);
304 $this->assertEquals('Attrappe 1-3-9', $row['title']);
305 }
306
307 /**
308 * Tests whether the getPage Hook is called correctly.
309 *
310 * @test
311 */
312 public function isGetPageHookCalled()
313 {
314 // Create a hook mock object
315 $getPageHookProphet = $this->prophesize(\stdClass::class);
316 $getPageHookProphet->willImplement(PageRepositoryGetPageHookInterface::class);
317 $getPageHookProphet->getPage_preProcess(42, false, Argument::type(PageRepository::class))->shouldBeCalled();
318 $getPageHookMock = $getPageHookProphet->reveal();
319 $className = get_class($getPageHookMock);
320
321 // Register hook mock object
322 GeneralUtility::addInstance($className, $getPageHookMock);
323 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'][] = $className;
324 $subject = new PageRepository();
325 $subject->getPage(42, false);
326 }
327
328 /**
329 * @test
330 */
331 public function initSetsPublicPropertyCorrectlyForWorkspacePreview()
332 {
333 $workspaceId = 2;
334 $subject = new PageRepository(new Context([
335 'workspace' => new WorkspaceAspect($workspaceId)
336 ]));
337
338 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages');
339
340 $expectedSQL = sprintf(
341 ' AND (%s = 0) AND ((%s = 0) OR (%s = 2)) AND (%s < 200)',
342 $connection->quoteIdentifier('pages.deleted'),
343 $connection->quoteIdentifier('pages.t3ver_wsid'),
344 $connection->quoteIdentifier('pages.t3ver_wsid'),
345 $connection->quoteIdentifier('pages.doktype')
346 );
347
348 $this->assertSame($expectedSQL, $subject->where_hid_del);
349 }
350
351 /**
352 * @test
353 */
354 public function initSetsPublicPropertyCorrectlyForLive()
355 {
356 $GLOBALS['SIM_ACCESS_TIME'] = 123;
357
358 $subject = new PageRepository(new Context());
359
360 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages');
361 $expectedSQL = sprintf(
362 ' AND ((%s = 0) AND (%s <= 0) AND (%s = 0) AND (%s <= 123) AND ((%s = 0) OR (%s > 123))) AND (%s < 200)',
363 $connection->quoteIdentifier('pages.deleted'),
364 $connection->quoteIdentifier('pages.t3ver_state'),
365 $connection->quoteIdentifier('pages.hidden'),
366 $connection->quoteIdentifier('pages.starttime'),
367 $connection->quoteIdentifier('pages.endtime'),
368 $connection->quoteIdentifier('pages.endtime'),
369 $connection->quoteIdentifier('pages.doktype')
370 );
371
372 $this->assertSame($expectedSQL, $subject->where_hid_del);
373 }
374
375 ////////////////////////////////
376 // Tests concerning workspaces
377 ////////////////////////////////
378
379 /**
380 * @test
381 */
382 public function previewShowsPagesFromLiveAndCurrentWorkspace()
383 {
384 // initialization
385 $wsid = 987654321;
386 // simulate calls from \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->fetch_the_id()
387 $subject = new PageRepository(new Context([
388 'workspace' => new WorkspaceAspect($wsid)
389 ]));
390
391 $pageRec = $subject->getPage(11);
392
393 $this->assertEquals(11, $pageRec['uid']);
394 $this->assertEquals(11, $pageRec['t3ver_oid']);
395 $this->assertEquals(987654321, $pageRec['t3ver_wsid']);
396 $this->assertEquals(-1, $pageRec['t3ver_state']);
397 $this->assertSame('First draft version', $pageRec['t3ver_label']);
398 }
399
400 /**
401 * @test
402 */
403 public function getWorkspaceVersionReturnsTheCorrectMethod()
404 {
405 // initialization
406 $wsid = 987654321;
407
408 // simulate calls from \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->fetch_the_id()
409 $subject = new PageRepository(new Context([
410 'workspace' => new WorkspaceAspect($wsid)
411 ]));
412
413 $pageRec = $subject->getWorkspaceVersionOfRecord($wsid, 'pages', 11);
414
415 $this->assertEquals(12, $pageRec['uid']);
416 $this->assertEquals(11, $pageRec['t3ver_oid']);
417 $this->assertEquals(987654321, $pageRec['t3ver_wsid']);
418 $this->assertEquals(-1, $pageRec['t3ver_state']);
419 $this->assertSame('First draft version', $pageRec['t3ver_label']);
420 }
421
422 ////////////////////////////////
423 // Tests concerning versioning
424 ////////////////////////////////
425
426 /**
427 * @test
428 */
429 public function enableFieldsHidesVersionedRecordsAndPlaceholders()
430 {
431 $table = $this->getUniqueId('aTable');
432 $GLOBALS['TCA'][$table] = [
433 'ctrl' => [
434 'versioningWS' => true
435 ]
436 ];
437
438 $subject = new PageRepository(new Context());
439
440 $conditions = $subject->enableFields($table);
441 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
442
443 $this->assertThat(
444 $conditions,
445 $this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.t3ver_state') . ' <= 0)'),
446 'Versioning placeholders'
447 );
448 $this->assertThat(
449 $conditions,
450 $this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.pid') . ' <> -1)'),
451 'Records from page -1'
452 );
453 }
454
455 /**
456 * @test
457 */
458 public function enableFieldsDoesNotHidePlaceholdersInPreview()
459 {
460 $table = $this->getUniqueId('aTable');
461 $GLOBALS['TCA'][$table] = [
462 'ctrl' => [
463 'versioningWS' => true
464 ]
465 ];
466
467 $subject = new PageRepository(new Context([
468 'workspace' => new WorkspaceAspect(13)
469 ]));
470
471 $conditions = $subject->enableFields($table);
472 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
473
474 $this->assertThat(
475 $conditions,
476 $this->logicalNot($this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.t3ver_state') . ' <= 0)')),
477 'No versioning placeholders'
478 );
479 $this->assertThat(
480 $conditions,
481 $this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.pid') . ' <> -1)'),
482 'Records from page -1'
483 );
484 }
485
486 /**
487 * @test
488 */
489 public function enableFieldsDoesFilterToCurrentAndLiveWorkspaceForRecordsInPreview()
490 {
491 $table = $this->getUniqueId('aTable');
492 $GLOBALS['TCA'][$table] = [
493 'ctrl' => [
494 'versioningWS' => true
495 ]
496 ];
497
498 $subject = new PageRepository(new Context([
499 'workspace' => new WorkspaceAspect(2)
500 ]));
501
502 $conditions = $subject->enableFields($table);
503 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
504
505 $this->assertThat(
506 $conditions,
507 $this->stringContains(' AND ((' . $connection->quoteIdentifier($table . '.t3ver_wsid') . ' = 0) OR (' . $connection->quoteIdentifier($table . '.t3ver_wsid') . ' = 2))'),
508 'No versioning placeholders'
509 );
510 }
511
512 /**
513 * @test
514 */
515 public function enableFieldsDoesNotHideVersionedRecordsWhenCheckingVersionOverlays()
516 {
517 $table = $this->getUniqueId('aTable');
518 $GLOBALS['TCA'][$table] = [
519 'ctrl' => [
520 'versioningWS' => true
521 ]
522 ];
523
524 $subject = new PageRepository(new Context([
525 'workspace' => new WorkspaceAspect(23)
526 ]));
527
528 $conditions = $subject->enableFields($table, -1, [], true);
529 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
530
531 $this->assertThat(
532 $conditions,
533 $this->logicalNot($this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.t3ver_state') . ' <= 0)')),
534 'No versioning placeholders'
535 );
536 $this->assertThat(
537 $conditions,
538 $this->logicalNot($this->stringContains(' AND (' . $connection->quoteIdentifier($table . '.pid') . ' <> -1)')),
539 'No records from page -1'
540 );
541 }
542
543 protected function assertOverlayRow($row)
544 {
545 $this->assertInternalType('array', $row);
546
547 $this->assertArrayHasKey('_PAGES_OVERLAY', $row);
548 $this->assertArrayHasKey('_PAGES_OVERLAY_UID', $row);
549 $this->assertArrayHasKey('_PAGES_OVERLAY_LANGUAGE', $row);
550
551 $this->assertTrue($row['_PAGES_OVERLAY']);
552 }
553
554 protected function assertNotOverlayRow($row)
555 {
556 $this->assertInternalType('array', $row);
557
558 $this->assertFalse(isset($row['_PAGES_OVERLAY']));
559 $this->assertFalse(isset($row['_PAGES_OVERLAY_UID']));
560 $this->assertFalse(isset($row['_PAGES_OVERLAY_LANGUAGE']));
561 }
562 }