‪TYPO3CMS  9.5
ContentObjectRendererTest.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 
24 
28 class ‪ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
29 {
33  protected ‪$subject;
34 
35  protected function ‪setUp()
36  {
37  parent::setUp();
38 
39  $typoScriptFrontendController = GeneralUtility::makeInstance(
40  TypoScriptFrontendController::class,
41  null,
42  1,
43  0
44  );
45  $typoScriptFrontendController->sys_page = GeneralUtility::makeInstance(PageRepository::class);
46  $typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
47  ‪$GLOBALS['TSFE'] = $typoScriptFrontendController;
48 
49  $this->subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
50  }
51 
58  public function ‪getQueryDataProvider(): array
59  {
60  $data = [
61  'testing empty conf' => [
62  'tt_content',
63  [],
64  [
65  'SELECT' => '*'
66  ]
67  ],
68  'testing #17284: adding uid/pid for workspaces' => [
69  'tt_content',
70  [
71  'selectFields' => 'header,bodytext'
72  ],
73  [
74  'SELECT' => 'header,bodytext, [tt_content].[uid] AS [uid], [tt_content].[pid] AS [pid], [tt_content].[t3ver_state] AS [t3ver_state]'
75  ]
76  ],
77  'testing #17284: no need to add' => [
78  'tt_content',
79  [
80  'selectFields' => 'tt_content.*'
81  ],
82  [
83  'SELECT' => 'tt_content.*'
84  ]
85  ],
86  'testing #17284: no need to add #2' => [
87  'tt_content',
88  [
89  'selectFields' => '*'
90  ],
91  [
92  'SELECT' => '*'
93  ]
94  ],
95  'testing #29783: joined tables, prefix tablename' => [
96  'tt_content',
97  [
98  'selectFields' => 'tt_content.header,be_users.username',
99  'join' => 'be_users ON tt_content.cruser_id = be_users.uid'
100  ],
101  [
102  'SELECT' => 'tt_content.header,be_users.username, [tt_content].[uid] AS [uid], [tt_content].[pid] AS [pid], [tt_content].[t3ver_state] AS [t3ver_state]'
103  ]
104  ],
105  'testing #34152: single count(*), add nothing' => [
106  'tt_content',
107  [
108  'selectFields' => 'count(*)'
109  ],
110  [
111  'SELECT' => 'count(*)'
112  ]
113  ],
114  'testing #34152: single max(crdate), add nothing' => [
115  'tt_content',
116  [
117  'selectFields' => 'max(crdate)'
118  ],
119  [
120  'SELECT' => 'max(crdate)'
121  ]
122  ],
123  'testing #34152: single min(crdate), add nothing' => [
124  'tt_content',
125  [
126  'selectFields' => 'min(crdate)'
127  ],
128  [
129  'SELECT' => 'min(crdate)'
130  ]
131  ],
132  'testing #34152: single sum(is_siteroot), add nothing' => [
133  'tt_content',
134  [
135  'selectFields' => 'sum(is_siteroot)'
136  ],
137  [
138  'SELECT' => 'sum(is_siteroot)'
139  ]
140  ],
141  'testing #34152: single avg(crdate), add nothing' => [
142  'tt_content',
143  [
144  'selectFields' => 'avg(crdate)'
145  ],
146  [
147  'SELECT' => 'avg(crdate)'
148  ]
149  ],
150  'single distinct, add nothing' => [
151  'tt_content',
152  [
153  'selectFields' => 'DISTINCT crdate'
154  ],
155  [
156  'SELECT' => 'DISTINCT crdate'
157  ]
158  ]
159  ];
160 
161  return $data;
162  }
163 
173  public function ‪getQuery(string $table, array $conf, array $expected)
174  {
175  ‪$GLOBALS['TCA'] = [
176  'pages' => [
177  'ctrl' => [
178  'enablecolumns' => [
179  'disabled' => 'hidden'
180  ]
181  ]
182  ],
183  'tt_content' => [
184  'ctrl' => [
185  'enablecolumns' => [
186  'disabled' => 'hidden'
187  ],
188  'versioningWS' => true
189  ]
190  ],
191  ];
192 
193  $result = $this->subject->getQuery($table, $conf, true);
194 
195  $databasePlatform = (new ConnectionPool())->getConnectionForTable('tt_content')->getDatabasePlatform();
196  foreach ($expected as $field => $value) {
197  if (!($databasePlatform instanceof \Doctrine\DBAL\Platforms\SQLServerPlatform)) {
198  // Replace the MySQL backtick quote character with the actual quote character for the DBMS,
199  if ($field === 'SELECT') {
200  $quoteChar = $databasePlatform->getIdentifierQuoteCharacter();
201  $value = str_replace(['[', ']'], [$quoteChar, $quoteChar], $value);
202  }
203  }
204  $this->assertEquals($value, $result[$field]);
205  }
206  }
207 
212  {
213  $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList']);
214  $this->subject->start([], 'tt_content');
215 
216  $conf = [
217  'recursive' => '15',
218  'pidInList' => '16, -35'
219  ];
220 
221  $this->subject->expects($this->at(0))
222  ->method('getTreeList')
223  ->with(-16, 15)
224  ->will($this->returnValue('15,16'));
225  $this->subject->expects($this->at(1))
226  ->method('getTreeList')
227  ->with(-35, 15)
228  ->will($this->returnValue('15,35'));
229 
230  $this->subject->getQuery('tt_content', $conf, true);
231  }
232 
237  {
238  ‪$GLOBALS['TSFE']->id = 27;
239 
240  $this->subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['getTreeList']);
241  $this->subject->start([], 'tt_content');
242 
243  $conf = [
244  'pidInList' => 'this',
245  'recursive' => '4'
246  ];
247 
248  $this->subject->expects($this->once())
249  ->method('getTreeList')
250  ->with(-27)
251  ->will($this->returnValue('27'));
252 
253  $this->subject->getQuery('tt_content', $conf, true);
254  }
255 
260  {
261  return [
262  [
263  [
264  'tt_content' => [
265  'ctrl' => [
266  ],
267  'columns' => [
268  ]
269  ],
270  ],
271  'tt_content',
272  [
273  'uidInList' => '42',
274  'pidInList' => 43,
275  'where' => 'tt_content.cruser_id=5',
276  'groupBy' => 'tt_content.title',
277  'orderBy' => 'tt_content.sorting',
278  ],
279  'WHERE (`tt_content`.`uid` IN (42)) AND (`tt_content`.`pid` IN (43)) AND (tt_content.cruser_id=5) GROUP BY `tt_content`.`title` ORDER BY `tt_content`.`sorting`',
280  ],
281  [
282  [
283  'tt_content' => [
284  'ctrl' => [
285  'delete' => 'deleted',
286  'enablecolumns' => [
287  'disabled' => 'hidden',
288  'starttime' => 'startdate',
289  'endtime' => 'enddate',
290  ],
291  'languageField' => 'sys_language_uid',
292  'transOrigPointerField' => 'l18n_parent',
293  ],
294  'columns' => [
295  ]
296  ],
297  ],
298  'tt_content',
299  [
300  'uidInList' => 42,
301  'pidInList' => 43,
302  'where' => 'tt_content.cruser_id=5',
303  'groupBy' => 'tt_content.title',
304  'orderBy' => 'tt_content.sorting',
305  ],
306  'WHERE (`tt_content`.`uid` IN (42)) AND (`tt_content`.`pid` IN (43)) AND (tt_content.cruser_id=5) AND (`tt_content`.`sys_language_uid` = 13) AND ((`tt_content`.`deleted` = 0) AND (`tt_content`.`hidden` = 0) AND (`tt_content`.`startdate` <= 4242) AND ((`tt_content`.`enddate` = 0) OR (`tt_content`.`enddate` > 4242))) GROUP BY `tt_content`.`title` ORDER BY `tt_content`.`sorting`',
307  ],
308  [
309  [
310  'tt_content' => [
311  'ctrl' => [
312  'languageField' => 'sys_language_uid',
313  'transOrigPointerField' => 'l18n_parent',
314  ],
315  'columns' => [
316  ]
317  ],
318  ],
319  'tt_content',
320  [
321  'uidInList' => 42,
322  'pidInList' => 43,
323  'where' => 'tt_content.cruser_id=5',
324  'languageField' => 0,
325  ],
326  'WHERE (`tt_content`.`uid` IN (42)) AND (`tt_content`.`pid` IN (43)) AND (tt_content.cruser_id=5)',
327  ],
328  ];
329  }
330 
335  {
336  return [
337  'Link to page' => [
338  'My page',
339  [
340  'parameter' => 42,
341  ],
342  [
343  'uid' => 42,
344  'title' => 'Page title',
345  ],
346  '<a href="index.php?id=42">My page</a>',
347  ],
348  'Link to page without link text' => [
349  '',
350  [
351  'parameter' => 42,
352  ],
353  [
354  'uid' => 42,
355  'title' => 'Page title',
356  ],
357  '<a href="index.php?id=42">Page title</a>',
358  ],
359  'Link to page with attributes' => [
360  'My page',
361  [
362  'parameter' => '42',
363  'ATagParams' => 'class="page-class"',
364  'target' => '_self',
365  'title' => 'Link to internal page',
366  ],
367  [
368  'uid' => 42,
369  'title' => 'Page title',
370  ],
371  '<a href="index.php?id=42" title="Link to internal page" target="_self" class="page-class">My page</a>',
372  ],
373  'Link to page with attributes in parameter' => [
374  'My page',
375  [
376  'parameter' => '42 _self page-class "Link to internal page"',
377  ],
378  [
379  'uid' => 42,
380  'title' => 'Page title',
381  ],
382  '<a href="index.php?id=42" title="Link to internal page" target="_self" class="page-class">My page</a>',
383  ],
384  'Link to page with bold tag in title' => [
385  '',
386  [
387  'parameter' => 42,
388  ],
389  [
390  'uid' => 42,
391  'title' => 'Page <b>title</b>',
392  ],
393  '<a href="index.php?id=42">Page <b>title</b></a>',
394  ],
395  'Link to page with script tag in title' => [
396  '',
397  [
398  'parameter' => 42,
399  ],
400  [
401  'uid' => 42,
402  'title' => '<script>alert(123)</script>Page title',
403  ],
404  '<a href="index.php?id=42">&lt;script&gt;alert(123)&lt;/script&gt;Page title</a>',
405  ],
406  ];
407  }
408 
417  public function ‪typolinkReturnsCorrectLinksForPages($linkText, $configuration, $pageArray, $expectedResult)
418  {
419  // @todo Merge with existing link generation test
420  // reason for failing is, that PageLinkBuilder is using a context-specific
421  // instance of PageRepository instead of reusing a shared global instance
422  $this->markTestIncomplete('This test has side effects and is based on non-asserted assumptions');
423 
424  $pageRepositoryMockObject = $this->getMockBuilder(PageRepository::class)
425  ->setMethods(['getPage'])
426  ->getMock();
427  $pageRepositoryMockObject->expects($this->any())->method('getPage')->willReturn($pageArray);
428 
429  $typoScriptFrontendController = $this->getMockBuilder(TypoScriptFrontendController::class)
430  ->setConstructorArgs([null, 1, 0])
431  ->setMethods(['dummy'])
432  ->getMock();
433  $typoScriptFrontendController->config = [
434  'config' => [],
435  ];
436  $typoScriptFrontendController->sys_page = $pageRepositoryMockObject;
437  $typoScriptFrontendController->tmpl = GeneralUtility::makeInstance(TemplateService::class);
438  $typoScriptFrontendController->tmpl->setup = [
439  'lib.' => [
440  'parseFunc.' => $this->‪getLibParseFunc(),
441  ],
442  ];
443  ‪$GLOBALS['TSFE'] = $typoScriptFrontendController;
444 
445  ‪$subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
446  $this->assertEquals($expectedResult, ‪$subject->‪typoLink($linkText, $configuration));
447  }
448 
453  {
454  $expected = '<a href="mailto:test@example.com">Send me an email</a>';
455  ‪$subject = new ContentObjectRenderer();
456  $result = ‪$subject->‪typoLink('Send me an email', ['parameter' => 'mailto:test@example.com']);
457  self::assertEquals($expected, $result);
458 
459  $result = ‪$subject->‪typoLink('Send me an email', ['parameter' => 'test@example.com']);
460  self::assertEquals($expected, $result);
461  }
462 
467  {
468  $tsfe = $this->getMockBuilder(TypoScriptFrontendController::class)->disableOriginalConstructor()->getMock();
469  ‪$subject = new ContentObjectRenderer($tsfe);
470 
471  $tsfe->spamProtectEmailAddresses = 1;
472  $result = ‪$subject->‪typoLink('Send me an email', ['parameter' => 'mailto:test@example.com']);
473  self::assertEquals('<a href="javascript:linkTo_UnCryptMailto(%27nbjmup%2BuftuAfybnqmf%5C%2Fdpn%27);">Send me an email</a>', $result);
474 
475  $tsfe->spamProtectEmailAddresses = 'ascii';
476  $result = ‪$subject->‪typoLink('Send me an email', ['parameter' => 'mailto:test@example.com']);
477  self::assertEquals('<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#116;&#101;&#115;&#116;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;">Send me an email</a>', $result);
478  }
479 
484  {
485  // @todo Merge with existing link generation test
486  // reason for failing is, that PageLinkBuilder is using a context-specific
487  // instance of PageRepository instead of reusing a shared global instance
488  $this->markTestIncomplete('This test has side effects and is based on non-asserted assumptions');
489 
490  $pageRepositoryMockObject = $this->getMockBuilder(PageRepository::class)
491  ->setMethods(['getPage'])
492  ->getMock();
493  $pageRepositoryMockObject->expects($this->any())->method('getPage')->willReturn([
494  'uid' => 1,
495  'title' => 'Page title',
496  ]);
497 
498  $templateServiceMockObject = $this->getMockBuilder(TemplateService::class)
499  ->getMock();
500  $templateServiceMockObject->setup = [
501  'lib.' => [
502  'parseFunc.' => $this->‪getLibParseFunc(),
503  ],
504  ];
505 
506  ‪$subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
507  $pageLinkBuilder = $this->getMockBuilder(PageLinkBuilder::class)
508  ->setMethods(['createTotalUrlAndLinkData'])
509  ->setConstructorArgs([‪$subject])
510  ->getMock();
511  $pageLinkBuilder->expects($this::once())->method('createTotalUrlAndLinkData')->willReturn([
512  'url' => '/index.php?id=1',
513  'target' => '',
514  'type' => '',
515  'orig_type' => '',
516  'no_cache' => '',
517  'linkVars' => '',
518  'sectionIndex' => '',
519  'totalURL' => '/',
520  ]);
521  GeneralUtility::addInstance(PageLinkBuilder::class, $pageLinkBuilder);
522 
523  $typoScriptFrontendController = $this->getMockBuilder(TypoScriptFrontendController::class)
524  ->setConstructorArgs([null, 1, 0])
525  ->setMethods(['dummy'])
526  ->getMock();
527  $typoScriptFrontendController->config = [
528  'config' => [],
529  ];
530  $typoScriptFrontendController->sys_page = $pageRepositoryMockObject;
531  $typoScriptFrontendController->tmpl = $templateServiceMockObject;
532  ‪$GLOBALS['TSFE'] = $typoScriptFrontendController;
533 
534  $configuration = [
535  'parameter' => 1,
536  'section' => 'content',
537  ];
538 
539  $this->assertEquals('<a href="#content">Page title</a>', ‪$subject->‪typoLink('', $configuration));
540  }
541 
546  {
547  $tsfe = $this->getMockBuilder(TypoScriptFrontendController::class)->disableOriginalConstructor()->getMock();
548  ‪$subject = new ContentObjectRenderer($tsfe);
549  ‪$subject->‪start([], 'tt_content');
550 
551  $expected = '';
552  $actual = ‪$subject->‪searchWhere('ab', 'header,bodytext', 'tt_content');
553  $this->assertEquals($expected, $actual);
554  }
555 
559  protected function ‪getLibParseFunc()
560  {
561  return [
562  'makelinks' => '1',
563  'makelinks.' => [
564  'http.' => [
565  'keep' => '{$styles.content.links.keep}',
566  'extTarget' => '',
567  'mailto.' => [
568  'keep' => 'path',
569  ],
570  ],
571  ],
572  'tags' => [
573  'link' => 'TEXT',
574  'link.' => [
575  'current' => '1',
576  'typolink.' => [
577  'parameter.' => [
578  'data' => 'parameters : allParams',
579  ],
580  ],
581  'parseFunc.' => [
582  'constants' => '1',
583  ],
584  ],
585  ],
586 
587  'allowTags' => 'a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var',
588  'denyTags' => '*',
589  'sword' => '<span class="csc-sword">|</span>',
590  'constants' => '1',
591  'nonTypoTagStdWrap.' => [
592  'HTMLparser' => '1',
593  'HTMLparser.' => [
594  'keepNonMatchedTags' => '1',
595  'htmlSpecialChars' => '2',
596  ],
597  ],
598  ];
599  }
600 }
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksForPages
‪typolinkReturnsCorrectLinksForPages($linkText, $configuration, $pageArray, $expectedResult)
Definition: ContentObjectRendererTest.php:416
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\start
‪start($data, $table='')
Definition: ContentObjectRenderer.php:532
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinkForEmails
‪typolinkReturnsCorrectLinkForEmails()
Definition: ContentObjectRendererTest.php:451
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinkForSectionToHomePageWithUrlRewriting
‪typolinkReturnsCorrectLinkForSectionToHomePageWithUrlRewriting()
Definition: ContentObjectRendererTest.php:482
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQueryCallsGetTreeListWithNegativeValuesIfRecursiveIsSet
‪getQueryCallsGetTreeListWithNegativeValuesIfRecursiveIsSet()
Definition: ContentObjectRendererTest.php:210
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\typoLink
‪string typoLink($linkText, $conf)
Definition: ContentObjectRenderer.php:5393
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\setUp
‪setUp()
Definition: ContentObjectRendererTest.php:34
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getLibParseFunc
‪array getLibParseFunc()
Definition: ContentObjectRendererTest.php:558
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQuery
‪getQuery(string $table, array $conf, array $expected)
Definition: ContentObjectRendererTest.php:172
‪TYPO3\CMS\Frontend\Page\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinkForSpamEncryptedEmails
‪typolinkReturnsCorrectLinkForSpamEncryptedEmails()
Definition: ContentObjectRendererTest.php:465
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQueryDataProvider
‪array getQueryDataProvider()
Definition: ContentObjectRendererTest.php:57
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest
Definition: ContentObjectRendererTest.php:29
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getWhereReturnCorrectQueryDataProvider
‪array getWhereReturnCorrectQueryDataProvider()
Definition: ContentObjectRendererTest.php:258
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksForPagesDataProvider
‪array typolinkReturnsCorrectLinksForPagesDataProvider()
Definition: ContentObjectRendererTest.php:333
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\$subject
‪ContentObjectRenderer $subject
Definition: ContentObjectRendererTest.php:32
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:50
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:97
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:91
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\searchWhereWithTooShortSearchWordWillReturnValidWhereStatement
‪searchWhereWithTooShortSearchWordWillReturnValidWhereStatement()
Definition: ContentObjectRendererTest.php:544
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQueryCallsGetTreeListWithCurrentPageIfThisIsSet
‪getQueryCallsGetTreeListWithCurrentPageIfThisIsSet()
Definition: ContentObjectRendererTest.php:235
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject
Definition: ContentObjectRendererTest.php:2
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\searchWhere
‪string searchWhere($searchWords, $searchFieldList, $searchTable)
Definition: ContentObjectRenderer.php:6496
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45