‪TYPO3CMS  ‪main
ContentObjectRendererTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
22 use Psr\EventDispatcher\EventDispatcherInterface;
23 use Psr\Http\Message\ServerRequestInterface;
24 use Psr\Log\NullLogger;
25 use Symfony\Component\DependencyInjection\Container;
32 use TYPO3\CMS\Core\LinkHandling\TypoLinkCodecService;
50 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
51 
52 final class ‪ContentObjectRendererTest extends FunctionalTestCase
53 {
55 
56  protected const ‪LANGUAGE_PRESETS = [
57  'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8'],
58  ];
59 
60  protected array ‪$pathsToProvideInTestInstance = ['typo3/sysext/frontend/Tests/Functional/Fixtures/Images' => 'fileadmin/user_upload'];
61 
62  protected function ‪setUp(): void
63  {
64  parent::setUp();
65  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
66  $this->setUpBackendUser(1);
68  'test',
69  $this->‪buildSiteConfiguration(1, '/'),
70  [
71  $this->‪buildDefaultLanguageConfiguration('EN', '/en/'),
72  ],
73  $this->‪buildErrorHandlingConfiguration('Fluid', [404]),
74  );
75  GeneralUtility::flushInternalRuntimeCaches();
76  }
77 
78  protected function ‪getPreparedRequest(): ServerRequestInterface
79  {
80  $request = new ‪ServerRequest('http://example.com/en/', 'GET', null, [], ['HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/en/']);
81  return $request->withQueryParams(['id' => 1])->withAttribute('normalizedParams', ‪NormalizedParams::createFromRequest($request));
82  }
83 
84  public static function ‪getQueryDataProvider(): array
85  {
86  return [
87  'testing empty conf' => [
88  'tt_content',
89  [],
90  [
91  'SELECT' => '*',
92  ],
93  ],
94  'testing #17284: adding uid/pid for workspaces' => [
95  'tt_content',
96  [
97  'selectFields' => 'header,bodytext',
98  ],
99  [
100  'SELECT' => 'header,bodytext, [tt_content].[uid] AS [uid], [tt_content].[pid] AS [pid], [tt_content].[t3ver_state] AS [t3ver_state]',
101  ],
102  ],
103  'testing #17284: no need to add' => [
104  'tt_content',
105  [
106  'selectFields' => 'tt_content.*',
107  ],
108  [
109  'SELECT' => 'tt_content.*',
110  ],
111  ],
112  'testing #17284: no need to add #2' => [
113  'tt_content',
114  [
115  'selectFields' => '*',
116  ],
117  [
118  'SELECT' => '*',
119  ],
120  ],
121  'testing #29783: joined tables, prefix tablename' => [
122  'tt_content',
123  [
124  'selectFields' => 'tt_content.header,be_users.username',
125  'join' => 'be_users ON tt_content.cruser_id = be_users.uid',
126  ],
127  [
128  'SELECT' => 'tt_content.header,be_users.username, [tt_content].[uid] AS [uid], [tt_content].[pid] AS [pid], [tt_content].[t3ver_state] AS [t3ver_state]',
129  ],
130  ],
131  'testing #34152: single count(*), add nothing' => [
132  'tt_content',
133  [
134  'selectFields' => 'count(*)',
135  ],
136  [
137  'SELECT' => 'count(*)',
138  ],
139  ],
140  'testing #34152: single max(crdate), add nothing' => [
141  'tt_content',
142  [
143  'selectFields' => 'max(crdate)',
144  ],
145  [
146  'SELECT' => 'max(crdate)',
147  ],
148  ],
149  'testing #34152: single min(crdate), add nothing' => [
150  'tt_content',
151  [
152  'selectFields' => 'min(crdate)',
153  ],
154  [
155  'SELECT' => 'min(crdate)',
156  ],
157  ],
158  'testing #34152: single sum(is_siteroot), add nothing' => [
159  'tt_content',
160  [
161  'selectFields' => 'sum(is_siteroot)',
162  ],
163  [
164  'SELECT' => 'sum(is_siteroot)',
165  ],
166  ],
167  'testing #34152: single avg(crdate), add nothing' => [
168  'tt_content',
169  [
170  'selectFields' => 'avg(crdate)',
171  ],
172  [
173  'SELECT' => 'avg(crdate)',
174  ],
175  ],
176  'single distinct, add nothing' => [
177  'tt_content',
178  [
179  'selectFields' => 'DISTINCT crdate',
180  ],
181  [
182  'SELECT' => 'DISTINCT crdate',
183  ],
184  ],
185  'testing #96321: pidInList=root does not raise PHP 8 warning' => [
186  'tt_content',
187  [
188  'selectFields' => '*',
189  'recursive' => '5',
190  'pidInList' => 'root',
191  ],
192  [
193  'SELECT' => '*',
194  ],
195  ],
196  ];
197  }
198 
202  #[DataProvider('getQueryDataProvider')]
203  #[Test]
204  public function ‪getQuery(string $table, array $conf, array $expected): void
205  {
206  ‪$GLOBALS['TCA'] = [
207  'pages' => [
208  'ctrl' => [
209  'enablecolumns' => [
210  'disabled' => 'hidden',
211  ],
212  ],
213  ],
214  'tt_content' => [
215  'ctrl' => [
216  'enablecolumns' => [
217  'disabled' => 'hidden',
218  ],
219  'versioningWS' => true,
220  ],
221  ],
222  ];
223 
224  $typoScriptFrontendController = GeneralUtility::makeInstance(TypoScriptFrontendController::class);
225  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class, $typoScriptFrontendController);
226  $request = $this->‪getPreparedRequest();
227  $pageInformation = new ‪PageInformation();
228  $pageInformation->setId(0);
229  $pageInformation->setContentFromPid(0);
230  $request = $request->withAttribute('frontend.page.information', $pageInformation);
231  $subject->setRequest($request);
232 
233  $result = $subject->getQuery($table, $conf, true);
234 
235  $databasePlatform = (new ‪ConnectionPool())->getConnectionForTable('tt_content')->getDatabasePlatform();
236  $identifierQuoteCharacter = (new ‪PlatformHelper())->getIdentifierQuoteCharacter($databasePlatform);
237  foreach ($expected as $field => $value) {
238  // Replace the TYPO3 quote character with the actual quote character for the DBMS,
239  if ($field === 'SELECT') {
240  $quoteChar = $identifierQuoteCharacter;
241  $value = str_replace(['[', ']'], [$quoteChar, $quoteChar], $value);
242  }
243  self::assertEquals($value, $result[$field]);
244  }
245  }
246 
247  #[Test]
249  {
250  $subject = new ‪ContentObjectRenderer();
251  $subject->setRequest($this->‪getPreparedRequest());
252  $linkResult = $subject->typoLink('', ['parameter' => 'https://example.tld', 'returnLast' => 'result']);
253  self::assertInstanceOf(LinkResultInterface::class, $linkResult);
254  }
255 
256  #[Test]
258  {
259  $linkService = $this->getMockBuilder(LinkService::class)->disableOriginalConstructor()->getMock();
260  $linkService->method('resolve')->with('foo')->willThrowException(new ‪InvalidPathException('', 1666303735));
261  $linkFactory = new ‪LinkFactory($linkService, $this->get(EventDispatcherInterface::class), $this->get(TypoLinkCodecService::class), $this->get('cache.runtime'), $this->get(SiteFinder::class));
262  $linkFactory->setLogger(new NullLogger());
263  GeneralUtility::addInstance(LinkFactory::class, $linkFactory);
264  $subject = new ‪ContentObjectRenderer();
265  $subject->setRequest($this->‪getPreparedRequest());
266  self::assertSame('foo', $subject->typoLink('foo', ['parameter' => 'foo']));
267  }
268 
269  #[Test]
271  {
272  $linkService = $this->getMockBuilder(LinkService::class)->disableOriginalConstructor()->getMock();
273  $linkService->method('resolve')->with('foo')->willThrowException(new ‪InvalidPathException('', 1666303765));
274  $linkFactory = new ‪LinkFactory($linkService, $this->get(EventDispatcherInterface::class), $this->get(TypoLinkCodecService::class), $this->get('cache.runtime'), $this->get(SiteFinder::class));
275  $logger = $this->getMockBuilder(Logger::class)->disableOriginalConstructor()->getMock();
276  $logger->expects(self::atLeastOnce())->method('warning')->with('The link could not be generated', self::anything());
277  $linkFactory->setLogger($logger);
278  GeneralUtility::addInstance(LinkFactory::class, $linkFactory);
279  $subject = new ‪ContentObjectRenderer();
280  $subject->setRequest($this->‪getPreparedRequest());
281  self::assertSame('foo', $subject->typoLink('foo', ['parameter' => 'foo']));
282  }
283 
284  public static function ‪typolinkReturnsCorrectLinksDataProvider(): array
285  {
286  return [
287  'Link to url' => [
288  'TYPO3',
289  [
290  'directImageLink' => false,
291  'parameter' => 'http://typo3.org',
292  ],
293  '<a href="http://typo3.org">TYPO3</a>',
294  ],
295  'Link to url without schema' => [
296  'TYPO3',
297  [
298  'directImageLink' => false,
299  'parameter' => 'typo3.org',
300  ],
301  '<a href="http://typo3.org">TYPO3</a>',
302  ],
303  'Link to url without link text' => [
304  '',
305  [
306  'directImageLink' => false,
307  'parameter' => 'http://typo3.org',
308  ],
309  '<a href="http://typo3.org">http://typo3.org</a>',
310  ],
311  'Link to url with attributes' => [
312  'TYPO3',
313  [
314  'parameter' => 'http://typo3.org',
315  'ATagParams' => 'class="url-class"',
316  'extTarget' => '_blank',
317  'title' => 'Open new window',
318  ],
319  '<a href="http://typo3.org" target="_blank" class="url-class" rel="noreferrer" title="Open new window">TYPO3</a>',
320  ],
321  'Link to url with attributes and custom target name' => [
322  'TYPO3',
323  [
324  'parameter' => 'http://typo3.org',
325  'ATagParams' => 'class="url-class"',
326  'extTarget' => 'someTarget',
327  'title' => 'Open new window',
328  ],
329  '<a href="http://typo3.org" target="someTarget" class="url-class" rel="noreferrer" title="Open new window">TYPO3</a>',
330  ],
331  'Link to url with attributes in parameter' => [
332  'TYPO3',
333  [
334  'parameter' => 'http://typo3.org _blank url-class "Open new window"',
335  ],
336  '<a href="http://typo3.org" target="_blank" rel="noreferrer" title="Open new window" class="url-class">TYPO3</a>',
337  ],
338  'Link to url with attributes in parameter and custom target name' => [
339  'TYPO3',
340  [
341  'parameter' => 'http://typo3.org someTarget url-class "Open new window"',
342  ],
343  '<a href="http://typo3.org" target="someTarget" rel="noreferrer" title="Open new window" class="url-class">TYPO3</a>',
344  ],
345  'Link to url with script tag' => [
346  '',
347  [
348  'directImageLink' => false,
349  'parameter' => 'http://typo3.org<script>alert(123)</script>',
350  ],
351  '<a href="http://typo3.org&lt;script&gt;alert(123)&lt;/script&gt;">http://typo3.org&lt;script&gt;alert(123)&lt;/script&gt;</a>',
352  ],
353  'Link to email address' => [
354  'Email address',
355  [
356  'parameter' => 'foo@example.com',
357  ],
358  '<a href="mailto:foo@example.com">Email address</a>',
359  ],
360  'Link to email with mailto' => [
361  'Send me an email',
362  [
363  'parameter' => 'mailto:test@example.com',
364  ],
365  '<a href="mailto:test@example.com">Send me an email</a>',
366  ],
367  'Link to email address with subject + cc' => [
368  'Email address',
369  [
370  'parameter' => 'foo@bar.org?subject=This%20is%20a%20test',
371  ],
372  '<a href="mailto:foo@bar.org?subject=This%20is%20a%20test">Email address</a>',
373  ],
374  'Link to email address without link text' => [
375  '',
376  [
377  'parameter' => 'foo@bar.org',
378  ],
379  '<a href="mailto:foo@bar.org">foo@bar.org</a>',
380  ],
381  'Link to email with attributes' => [
382  'Email address',
383  [
384  'parameter' => 'foo@bar.org',
385  'ATagParams' => 'class="email-class"',
386  'title' => 'Write an email',
387  ],
388  '<a href="mailto:foo@bar.org" class="email-class" title="Write an email">Email address</a>',
389  ],
390  'Link to email with attributes in parameter' => [
391  'Email address',
392  [
393  'parameter' => 'foo@bar.org - email-class "Write an email"',
394  ],
395  '<a href="mailto:foo@bar.org" title="Write an email" class="email-class">Email address</a>',
396  ],
397  'Link url using stdWrap' => [
398  'TYPO3',
399  [
400  'parameter' => 'http://typo3.org',
401  'parameter.' => [
402  'cObject' => 'TEXT',
403  'cObject.' => [
404  'value' => 'http://typo3.com',
405  ],
406  ],
407  ],
408  '<a href="http://typo3.com">TYPO3</a>',
409  ],
410  'Link url using stdWrap with class attribute in parameter' => [
411  'TYPO3',
412  [
413  'parameter' => 'http://typo3.org - url-class',
414  'parameter.' => [
415  'cObject' => 'TEXT',
416  'cObject.' => [
417  'value' => 'http://typo3.com',
418  ],
419  ],
420  ],
421  '<a href="http://typo3.com" class="url-class">TYPO3</a>',
422  ],
423  'Link url using stdWrap with class attribute in parameter and overridden target' => [
424  'TYPO3',
425  [
426  'parameter' => 'http://typo3.org default-target url-class',
427  'parameter.' => [
428  'cObject' => 'TEXT',
429  'cObject.' => [
430  'value' => 'http://typo3.com new-target different-url-class',
431  ],
432  ],
433  ],
434  '<a href="http://typo3.com" target="new-target" rel="noreferrer" class="different-url-class">TYPO3</a>',
435  ],
436  'Link url using stdWrap with class attribute in parameter and overridden target and returnLast' => [
437  'TYPO3',
438  [
439  'parameter' => 'http://typo3.org default-target url-class',
440  'parameter.' => [
441  'cObject' => 'TEXT',
442  'cObject.' => [
443  'value' => 'http://typo3.com new-target different-url-class',
444  ],
445  ],
446  'returnLast' => 'url',
447  ],
448  'http://typo3.com',
449  ],
450  'Open in new window' => [
451  'Nice Text',
452  [
453  'parameter' => 'https://example.com 13x84:target=myexample',
454  ],
455  '<a href="https://example.com" target="myexample" data-window-url="https://example.com" data-window-target="myexample" data-window-features="width=13,height=84" rel="noreferrer">Nice Text</a>',
456  ],
457  'Open in new window with window name' => [
458  'Nice Text',
459  [
460  'parameter' => 'https://example.com 13x84',
461  ],
462  '<a href="https://example.com" target="FEopenLink" data-window-url="https://example.com" data-window-target="FEopenLink" data-window-features="width=13,height=84" rel="noreferrer">Nice Text</a>',
463  ],
464  'Link to file' => [
465  'My file',
466  [
467  'directImageLink' => false,
468  'parameter' => 'fileadmin/foo.bar',
469  ],
470  '<a href="fileadmin/foo.bar">My file</a>',
471  ],
472  'Link to file without link text' => [
473  '',
474  [
475  'directImageLink' => false,
476  'parameter' => 'fileadmin/foo.bar',
477  ],
478  '<a href="fileadmin/foo.bar">fileadmin/foo.bar</a>',
479  ],
480  'Link to file with attributes' => [
481  'My file',
482  [
483  'parameter' => 'fileadmin/foo.bar',
484  'ATagParams' => 'class="file-class"',
485  'fileTarget' => '_blank',
486  'title' => 'Title of the file',
487  ],
488  '<a href="fileadmin/foo.bar" target="_blank" class="file-class" title="Title of the file">My file</a>',
489  ],
490  'Link to file with attributes and additional href' => [
491  'My file',
492  [
493  'parameter' => 'fileadmin/foo.bar',
494  'ATagParams' => 'href="foo-bar"',
495  'fileTarget' => '_blank',
496  'title' => 'Title of the file',
497  ],
498  '<a href="fileadmin/foo.bar" target="_blank" title="Title of the file">My file</a>',
499  ],
500  'Link to file with attributes and additional href and class' => [
501  'My file',
502  [
503  'parameter' => 'fileadmin/foo.bar',
504  'ATagParams' => 'href="foo-bar" class="file-class"',
505  'fileTarget' => '_blank',
506  'title' => 'Title of the file',
507  ],
508  '<a href="fileadmin/foo.bar" target="_blank" class="file-class" title="Title of the file">My file</a>',
509  ],
510  'Link to file with attributes and additional class and href' => [
511  'My file',
512  [
513  'parameter' => 'fileadmin/foo.bar',
514  'ATagParams' => 'class="file-class" href="foo-bar"',
515  'fileTarget' => '_blank',
516  'title' => 'Title of the file',
517  ],
518  '<a href="fileadmin/foo.bar" target="_blank" class="file-class" title="Title of the file">My file</a>',
519  ],
520  'Link to file with attributes and additional class and href and title' => [
521  'My file',
522  [
523  'parameter' => 'fileadmin/foo.bar',
524  'ATagParams' => 'class="file-class" href="foo-bar" title="foo-bar"',
525  'fileTarget' => '_blank',
526  'title' => 'Title of the file',
527  ],
528  '<a href="fileadmin/foo.bar" target="_blank" class="file-class" title="Title of the file">My file</a>',
529  ],
530  'Link to file with attributes and empty ATagParams' => [
531  'My file',
532  [
533  'parameter' => 'fileadmin/foo.bar',
534  'ATagParams' => '',
535  'fileTarget' => '_blank',
536  'title' => 'Title of the file',
537  ],
538  '<a href="fileadmin/foo.bar" target="_blank" title="Title of the file">My file</a>',
539  ],
540  'Link to file with attributes in parameter' => [
541  'My file',
542  [
543  'parameter' => 'fileadmin/foo.bar _blank file-class "Title of the file"',
544  ],
545  '<a href="fileadmin/foo.bar" target="_blank" title="Title of the file" class="file-class">My file</a>',
546  ],
547  'Link to file with script tag in name' => [
548  '',
549  [
550  'directImageLink' => false,
551  'parameter' => 'fileadmin/<script>alert(123)</script>',
552  ],
553  '<a href="fileadmin/&lt;script&gt;alert(123)&lt;/script&gt;">fileadmin/&lt;script&gt;alert(123)&lt;/script&gt;</a>',
554  ],
555  ];
556  }
557 
558  #[DataProvider('typolinkReturnsCorrectLinksDataProvider')]
559  #[Test]
560  public function ‪typolinkReturnsCorrectLinksAndUrls(string $linkText, array $configuration, string $expectedResult): void
561  {
562  $subject = new ‪ContentObjectRenderer();
563  $subject->setRequest($this->‪getPreparedRequest());
564  self::assertEquals($expectedResult, $subject->typoLink($linkText, $configuration));
565  }
566 
568  {
569  return [
570  'plain mail without mailto scheme' => [
571  [
572  'spamProtectEmailAddresses' => 0,
573  'spamProtectEmailAddresses_atSubst' => '',
574  'spamProtectEmailAddresses_lastDotSubst' => '',
575  ],
576  'some.body@test.typo3.org',
577  'some.body@test.typo3.org',
578  '<a href="mailto:some.body@test.typo3.org">some.body@test.typo3.org</a>',
579  ],
580  'plain mail with mailto scheme' => [
581  [
582  'spamProtectEmailAddresses' => 0,
583  'spamProtectEmailAddresses_atSubst' => '',
584  'spamProtectEmailAddresses_lastDotSubst' => '',
585  ],
586  'some.body@test.typo3.org',
587  'mailto:some.body@test.typo3.org',
588  '<a href="mailto:some.body@test.typo3.org">some.body@test.typo3.org</a>',
589  ],
590  'plain with at and dot substitution' => [
591  [
592  'spamProtectEmailAddresses' => 0,
593  'spamProtectEmailAddresses_atSubst' => '(at)',
594  'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
595  ],
596  'some.body@test.typo3.org',
597  'mailto:some.body@test.typo3.org',
598  '<a href="mailto:some.body@test.typo3.org">some.body@test.typo3.org</a>',
599  ],
600  'mono-alphabetic substitution offset +1' => [
601  [
602  'spamProtectEmailAddresses' => 1,
603  'spamProtectEmailAddresses_atSubst' => '',
604  'spamProtectEmailAddresses_lastDotSubst' => '',
605  ],
606  'some.body@test.typo3.org',
607  'mailto:some.body@test.typo3.org',
608  '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">some.body(at)test.typo3.org</a>',
609  ],
610  'mono-alphabetic substitution offset +1 with at substitution' => [
611  [
612  'spamProtectEmailAddresses' => 1,
613  'spamProtectEmailAddresses_atSubst' => '@',
614  'spamProtectEmailAddresses_lastDotSubst' => '',
615  ],
616  'some.body@test.typo3.org',
617  'mailto:some.body@test.typo3.org',
618  '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">some.body@test.typo3.org</a>',
619  ],
620  'mono-alphabetic substitution offset +1 with at and dot substitution' => [
621  [
622  'spamProtectEmailAddresses' => 1,
623  'spamProtectEmailAddresses_atSubst' => '(at)',
624  'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
625  ],
626  'some.body@test.typo3.org',
627  'mailto:some.body@test.typo3.org',
628  '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">some.body(at)test.typo3(dot)org</a>',
629  ],
630  'mono-alphabetic substitution offset -1 with at and dot substitution' => [
631  [
632  'spamProtectEmailAddresses' => -1,
633  'spamProtectEmailAddresses_atSubst' => '(at)',
634  'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
635  ],
636  'some.body@test.typo3.org',
637  'mailto:some.body@test.typo3.org',
638  '<a href="#" data-mailto-token="lzhksn9rnld-ancxZsdrs-sxon2-nqf" data-mailto-vector="-1">some.body(at)test.typo3(dot)org</a>',
639  ],
640  'mono-alphabetic substitution offset -1 with at and dot markup substitution' => [
641  [
642  'spamProtectEmailAddresses' => -1,
643  'spamProtectEmailAddresses_atSubst' => '<span class="at"></span>',
644  'spamProtectEmailAddresses_lastDotSubst' => '<span class="dot"></span>',
645  ],
646  'some.body@test.typo3.org',
647  'mailto:some.body@test.typo3.org',
648  '<a href="#" data-mailto-token="lzhksn9rnld-ancxZsdrs-sxon2-nqf" data-mailto-vector="-1">some.body<span class="at"></span>test.typo3<span class="dot"></span>org</a>',
649  ],
650  'mono-alphabetic substitution offset 2 with at and dot substitution and encoded subject' => [
651  [
652  'spamProtectEmailAddresses' => 2,
653  'spamProtectEmailAddresses_atSubst' => '(at)',
654  'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
655  ],
656  'some.body@test.typo3.org',
657  'mailto:some.body@test.typo3.org?subject=foo%20bar',
658  '<a href="#" data-mailto-token="ocknvq,uqog0dqfaBvguv0varq50qti?uwdlgev=hqq%42dct" data-mailto-vector="2">some.body(at)test.typo3(dot)org</a>',
659  ],
660  ];
661  }
662 
663  #[DataProvider('typolinkReturnsCorrectLinkForSpamEncryptedEmailsDataProvider')]
664  #[Test]
665  public function ‪typolinkReturnsCorrectLinkForSpamEncryptedEmails(array $tsfeConfig, string $linkText, string $parameter, string $expected): void
666  {
667  $frontendTypoScript = new ‪FrontendTypoScript(new ‪RootNode(), []);
668  $frontendTypoScript->setConfigArray($tsfeConfig);
669  $request = (new ‪ServerRequest())->withAttribute('frontend.typoscript', $frontendTypoScript);
670  $subject = new ‪ContentObjectRenderer();
671  $subject->setRequest($request);
672  self::assertEquals($expected, $subject->typoLink($linkText, ['parameter' => $parameter]));
673  }
674 
676  {
677  return [
678  'Link to file' => [
679  'My file',
680  [
681  'directImageLink' => false,
682  'parameter' => 'fileadmin/foo.bar',
683  ],
684  '/',
685  '<a href="/fileadmin/foo.bar">My file</a>',
686  ],
687  'Link to file with longer absRefPrefix' => [
688  'My file',
689  [
690  'directImageLink' => false,
691  'parameter' => 'fileadmin/foo.bar',
692  ],
693  '/sub/',
694  '<a href="/sub/fileadmin/foo.bar">My file</a>',
695  ],
696  'Link to absolute file' => [
697  'My file',
698  [
699  'directImageLink' => false,
700  'parameter' => '/images/foo.bar',
701  ],
702  '/',
703  '<a href="/images/foo.bar">My file</a>',
704  ],
705  'Link to absolute file with longer absRefPrefix' => [
706  'My file',
707  [
708  'directImageLink' => false,
709  'parameter' => '/images/foo.bar',
710  ],
711  '/sub/',
712  '<a href="/images/foo.bar">My file</a>',
713  ],
714  'Link to absolute file with identical longer absRefPrefix' => [
715  'My file',
716  [
717  'directImageLink' => false,
718  'parameter' => '/sub/fileadmin/foo.bar',
719  ],
720  '/sub/',
721  '<a href="/sub/fileadmin/foo.bar">My file</a>',
722  ],
723  'Link to file with empty absRefPrefix' => [
724  'My file',
725  [
726  'directImageLink' => false,
727  'parameter' => 'fileadmin/foo.bar',
728  ],
729  '',
730  '<a href="fileadmin/foo.bar">My file</a>',
731  ],
732  'Link to absolute file with empty absRefPrefix' => [
733  'My file',
734  [
735  'directImageLink' => false,
736  'parameter' => '/fileadmin/foo.bar',
737  ],
738  '',
739  '<a href="/fileadmin/foo.bar">My file</a>',
740  ],
741  'Link to file with attributes with absRefPrefix' => [
742  'My file',
743  [
744  'parameter' => 'fileadmin/foo.bar',
745  'ATagParams' => 'class="file-class"',
746  'title' => 'Title of the file',
747  ],
748  '/',
749  '<a href="/fileadmin/foo.bar" class="file-class" title="Title of the file">My file</a>',
750  ],
751  'Link to file with attributes with longer absRefPrefix' => [
752  'My file',
753  [
754  'parameter' => 'fileadmin/foo.bar',
755  'ATagParams' => 'class="file-class"',
756  'title' => 'Title of the file',
757  ],
758  '/sub/',
759  '<a href="/sub/fileadmin/foo.bar" class="file-class" title="Title of the file">My file</a>',
760  ],
761  'Link to absolute file with attributes with absRefPrefix' => [
762  'My file',
763  [
764  'parameter' => '/images/foo.bar',
765  'ATagParams' => 'class="file-class"',
766  'title' => 'Title of the file',
767  ],
768  '/',
769  '<a href="/images/foo.bar" class="file-class" title="Title of the file">My file</a>',
770  ],
771  'Link to absolute file with attributes with longer absRefPrefix' => [
772  'My file',
773  [
774  'parameter' => '/images/foo.bar',
775  'ATagParams' => 'class="file-class"',
776  'title' => 'Title of the file',
777  ],
778  '/sub/',
779  '<a href="/images/foo.bar" class="file-class" title="Title of the file">My file</a>',
780  ],
781  'Link to absolute file with attributes with identical longer absRefPrefix' => [
782  'My file',
783  [
784  'parameter' => '/sub/fileadmin/foo.bar',
785  'ATagParams' => 'class="file-class"',
786  'title' => 'Title of the file',
787  ],
788  '/sub/',
789  '<a href="/sub/fileadmin/foo.bar" class="file-class" title="Title of the file">My file</a>',
790  ],
791  ];
792  }
793 
794  #[DataProvider('typolinkReturnsCorrectLinksForFilesWithAbsRefPrefixDataProvider')]
795  #[Test]
796  public function ‪typolinkReturnsCorrectLinksForFilesWithAbsRefPrefix(string $linkText, array $configuration, string $absRefPrefix, string $expectedResult): void
797  {
798  $tsfe = $this->getMockBuilder(TypoScriptFrontendController::class)->disableOriginalConstructor()->getMock();
799  $tsfe->absRefPrefix = $absRefPrefix;
800  $request = new ‪ServerRequest();
801  $subject = new ‪ContentObjectRenderer($tsfe);
802  $subject->setRequest($request);
803  self::assertEquals($expectedResult, $subject->typoLink($linkText, $configuration));
804  }
805 
806  public static function ‪typoLinkProperlyEncodesLinkResultDataProvider(): array
807  {
808  return [
809  'Link to file' => [
810  'My file',
811  [
812  'directImageLink' => false,
813  'parameter' => '/fileadmin/foo.bar',
814  'returnLast' => 'result',
815  ],
816  json_encode([
817  'href' => '/fileadmin/foo.bar',
818  'target' => null,
819  'class' => null,
820  'title' => null,
821  'linkText' => 'My file',
822  'additionalAttributes' => [],
823  ]),
824  ],
825  'Link example' => [
826  'My example',
827  [
828  'directImageLink' => false,
829  'parameter' => 'https://example.tld',
830  'returnLast' => 'result',
831  ],
832  json_encode([
833  'href' => 'https://example.tld',
834  'target' => null,
835  'class' => null,
836  'title' => null,
837  'linkText' => 'My example',
838  'additionalAttributes' => [],
839  ]),
840  ],
841  'Link to file with attributes' => [
842  'My file',
843  [
844  'parameter' => '/fileadmin/foo.bar',
845  'ATagParams' => 'class="file-class"',
846  'returnLast' => 'result',
847  ],
848  json_encode([
849  'href' => '/fileadmin/foo.bar',
850  'target' => null,
851  'class' => 'file-class',
852  'title' => null,
853  'linkText' => 'My file',
854  'additionalAttributes' => [],
855  ]),
856  ],
857  'Link parsing' => [
858  'Url',
859  [
860  'parameter' => 'https://example.com _blank css-class "test title"',
861  'returnLast' => 'result',
862  ],
863  json_encode([
864  'href' => 'https://example.com',
865  'target' => '_blank',
866  'class' => 'css-class',
867  'title' => 'test title',
868  'linkText' => 'Url',
869  'additionalAttributes' => ['rel' => 'noreferrer'],
870  ]),
871  ],
872  ];
873  }
874 
875  #[DataProvider('typoLinkProperlyEncodesLinkResultDataProvider')]
876  #[Test]
877  public function ‪typoLinkProperlyEncodesLinkResult(string $linkText, array $configuration, string $expectedResult): void
878  {
879  $subject = new ‪ContentObjectRenderer();
880  $subject->setRequest($this->‪getPreparedRequest());
881  self::assertEquals($expectedResult, $subject->typoLink($linkText, $configuration));
882  }
883 
884  #[Test]
886  {
887  $tsfe = $this->getMockBuilder(TypoScriptFrontendController::class)->disableOriginalConstructor()->getMock();
888  $subject = new ‪ContentObjectRenderer($tsfe);
889  $subject->setRequest($this->‪getPreparedRequest());
890  $subject->start([], 'tt_content');
891 
892  $expected = '';
893  $actual = $subject->searchWhere('ab', 'header,bodytext', 'tt_content');
894  self::assertEquals($expected, $actual);
895  }
896 
897  #[Test]
898  public function ‪libParseFuncProperlyKeepsTagsUnescaped(): void
899  {
900  $tsfe = $this->getMockBuilder(TypoScriptFrontendController::class)->disableOriginalConstructor()->getMock();
901  $subject = new ‪ContentObjectRenderer($tsfe);
902  $typoScript = new ‪FrontendTypoScript(new ‪RootNode(), []);
903  $typoScript->setConfigArray([]);
904  $request = $this->‪getPreparedRequest()->withAttribute('frontend.typoscript', $typoScript);
905  $subject->setRequest($request);
906  $subject->setLogger(new NullLogger());
907  $input = 'This is a simple inline text, no wrapping configured';
908  $result = $subject->parseFunc($input, $this->‪getLibParseFunc());
909  self::assertEquals($input, $result);
910 
911  $input = '<p>A one liner paragraph</p>';
912  $result = $subject->parseFunc($input, $this->‪getLibParseFunc());
913  self::assertEquals($input, $result);
914 
915  $input = 'A one liner paragraph
916 And another one';
917  $result = $subject->parseFunc($input, $this->‪getLibParseFunc());
918  self::assertEquals($input, $result);
919 
920  $input = '<p>A one liner paragraph</p><p>And another one and the spacing is kept</p>';
921  $result = $subject->parseFunc($input, $this->‪getLibParseFunc());
922  self::assertEquals($input, $result);
923 
924  $input = '<p>text to a <a href="https://www.example.com">an external page</a>.</p>';
925  $result = $subject->parseFunc($input, $this->‪getLibParseFunc());
926  self::assertEquals($input, $result);
927  }
928 
929  protected function ‪getLibParseFunc(): array
930  {
931  return [
932  'htmlSanitize' => '1',
933  'makelinks' => '1',
934  'makelinks.' => [
935  'http.' => [
936  'keep' => '{$styles.content.links.keep}',
937  'extTarget' => '',
938  'mailto.' => [
939  'keep' => 'path',
940  ],
941  ],
942  ],
943  'tags.' => [
944  'link' => 'TEXT',
945  'link.' => [
946  'current' => '1',
947  'typolink.' => [
948  'parameter.' => [
949  'data' => 'parameters : allParams',
950  ],
951  ],
952  'parseFunc.' => [
953  'constants' => '1',
954  ],
955  ],
956  'a' => 'TEXT',
957  'a.' => [
958  'current' => '1',
959  'typolink.' => [
960  'parameter.' => [
961  'data' => 'parameters:href',
962  ],
963  ],
964  ],
965  ],
966 
967  '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',
968  'denyTags' => '*',
969  'sword' => '<span class="csc-sword">|</span>',
970  'constants' => '1',
971  'nonTypoTagStdWrap.' => [
972  'HTMLparser' => '1',
973  'HTMLparser.' => [
974  'keepNonMatchedTags' => '1',
975  'htmlSpecialChars' => '2',
976  ],
977  ],
978  ];
979  }
980 
981  public static function ‪checkIfReturnsExpectedValuesDataProvider(): iterable
982  {
983  yield 'isNull returns true if stdWrap returns null' => [
984  'configuration' => [
985  'isNull.' => [
986  'field' => 'unknown',
987  ],
988  ],
989  'expected' => true,
990  ];
991 
992  yield 'isNull returns false if stdWrap returns not null' => [
993  'configuration' => [
994  'isNull.' => [
995  'field' => 'known',
996  ],
997  ],
998  'expected' => false,
999  ];
1000  }
1001 
1002  #[DataProvider('checkIfReturnsExpectedValuesDataProvider')]
1003  #[Test]
1004  public function ‪checkIfReturnsExpectedValues(array $configuration, bool $expected): void
1005  {
1006  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1007  $subject->data = [
1008  'known' => 'somevalue',
1009  ];
1010  self::assertSame($expected, $subject->checkIf($configuration));
1011  }
1013  public static function ‪imageLinkWrapWrapsTheContentAsConfiguredDataProvider(): iterable
1014  {
1015  $width = 900;
1016  $height = 600;
1017  $processingWidth = $width . 'm';
1018  $processingHeight = $height . 'm';
1019  $defaultConfiguration = [
1020  'wrap' => '<a href="javascript:close();"> | </a>',
1021  'width' => $processingWidth,
1022  'height' => $processingHeight,
1023  'JSwindow' => '1',
1024  'JSwindow.' => [
1025  'newWindow' => '0',
1026  ],
1027  'crop.' => [
1028  'data' => 'file:current:crop',
1029  ],
1030  'linkParams.' => [
1031  'ATagParams.' => [
1032  'dataWrap' => 'class="lightbox" rel="lightbox[{field:uid}]"',
1033  ],
1034  ],
1035  'enable' => true,
1036  ];
1037  $imageTag = '<img class="image-embed-item" src="/fileadmin/_processed_/team-t3board10-processed.jpg" width="500" height="300" loading="lazy" alt="" />';
1038  $windowFeatures = 'width=' . $width . ',height=' . $height . ',status=0,menubar=0';
1039 
1040  $configurationEnableFalse = $defaultConfiguration;
1041  $configurationEnableFalse['enable'] = false;
1042  yield 'enable => false configuration returns image tag as is.' => [
1043  'content' => $imageTag,
1044  'configuration' => $configurationEnableFalse,
1045  'expected' => [$imageTag => true],
1046  ];
1047 
1048  yield 'image is wrapped with link tag.' => [
1049  'content' => $imageTag,
1050  'configuration' => $defaultConfiguration,
1051  'expected' => [
1052  '<a href="index.php?eID=tx_cms_showpic&amp;file=1' => true,
1053  $imageTag . '</a>' => true,
1054  'data-window-features="' . $windowFeatures => true,
1055  'data-window-target="thePicture"' => true,
1056  ' target="thePicture' => true,
1057  ],
1058  ];
1059 
1060  $paramsConfiguration = $defaultConfiguration;
1061  $windowFeaturesOverrides = 'width=420,status=1,menubar=1,foo=bar';
1062  $windowFeaturesOverriddenExpected = 'width=420,height=' . $height . ',status=1,menubar=1,foo=bar';
1063  $paramsConfiguration['JSwindow.']['params'] = $windowFeaturesOverrides;
1064  yield 'JSWindow.params overrides windowParams' => [
1065  'content' => $imageTag,
1066  'configuration' => $paramsConfiguration,
1067  'expected' => [
1068  'data-window-features="' . $windowFeaturesOverriddenExpected => true,
1069  ],
1070  ];
1071 
1072  $newWindowConfiguration = $defaultConfiguration;
1073  $newWindowConfiguration['JSwindow.']['newWindow'] = '1';
1074  yield 'data-window-target is not "thePicture" if newWindow = 1 but an md5 hash of the url.' => [
1075  'content' => $imageTag,
1076  'configuration' => $newWindowConfiguration,
1077  'expected' => [
1078  'data-window-target="thePicture' => false,
1079  ],
1080  ];
1081 
1082  $newWindowConfiguration = $defaultConfiguration;
1083  $newWindowConfiguration['JSwindow.']['expand'] = '20,40';
1084  $windowFeaturesExpand = 'width=' . ($width + 20) . ',height=' . ($height + 40) . ',status=0,menubar=0';
1085  yield 'expand increases the window size by its value' => [
1086  'content' => $imageTag,
1087  'configuration' => $newWindowConfiguration,
1088  'expected' => [
1089  'data-window-features="' . $windowFeaturesExpand => true,
1090  ],
1091  ];
1092 
1093  $directImageLinkConfiguration = $defaultConfiguration;
1094  $directImageLinkConfiguration['directImageLink'] = '1';
1095  yield 'Direct image link does not use eID and links directly to the image.' => [
1096  'content' => $imageTag,
1097  'configuration' => $directImageLinkConfiguration,
1098  'expected' => [
1099  'index.php?eID=tx_cms_showpic&amp;file=1' => false,
1100  '<a href="fileadmin/_processed_' => true,
1101  'data-window-url="fileadmin/_processed_' => true,
1102  ],
1103  ];
1104 
1105  // @todo Error: Object of class TYPO3\CMS\Core\Resource\FileReference could not be converted to string
1106  // $altUrlConfiguration = $defaultConfiguration;
1107  // $altUrlConfiguration['JSwindow.']['altUrl'] = '/alternative-url';
1108  // yield 'JSwindow.altUrl forces an alternative url.' => [
1109  // 'content' => $imageTag,
1110  // 'configuration' => $altUrlConfiguration,
1111  // 'expected' => [
1112  // '<a href="/alternative-url' => true,
1113  // 'data-window-url="/alternative-url' => true,
1114  // ],
1115  // ];
1116 
1117  $altUrlConfigurationNoDefault = $defaultConfiguration;
1118  $altUrlConfigurationNoDefault['JSwindow.']['altUrl'] = '/alternative-url';
1119  $altUrlConfigurationNoDefault['JSwindow.']['altUrl_noDefaultParams'] = '1';
1120  yield 'JSwindow.altUrl_noDefaultParams removes the default ?file= params' => [
1121  'content' => $imageTag,
1122  'configuration' => $altUrlConfigurationNoDefault,
1123  'expected' => [
1124  '<a href="/alternative-url' => true,
1125  'data-window-url="/alternative-url' => true,
1126  'data-window-url="/alternative-url?file=' => false,
1127  ],
1128  ];
1129 
1130  $targetConfiguration = $defaultConfiguration;
1131  $targetConfiguration['target'] = 'myTarget';
1132  yield 'Setting target overrides the default target "thePicture.' => [
1133  'content' => $imageTag,
1134  'configuration' => $targetConfiguration,
1135  'expected' => [
1136  ' target="myTarget"' => true,
1137  'data-window-target="thePicture"' => true,
1138  ],
1139  ];
1140 
1141  $parameters = [
1142  'sample' => '1',
1143  'width' => $processingWidth,
1144  'height' => $processingHeight,
1145  'effects' => 'gamma=1.3 | flip | rotate=180',
1146  'bodyTag' => '<body style="margin:0; background:#fff;">',
1147  'title' => 'My Title',
1148  'wrap' => '<div class="my-wrap">|</div>',
1149  'crop' => '{"default":{"cropArea":{"x":0,"y":0,"width":1,"height":1},"selectedRatio":"NaN","focusArea":null}}',
1150  ];
1151  $parameterConfiguration = array_replace($defaultConfiguration, $parameters);
1152  $expectedParameters = $parameters;
1153  $expectedParameters['sample'] = 1;
1154  yield 'Setting one of [width, height, effects, bodyTag, title, wrap, crop, sample] will add them to the parameter list.' => [
1155  'content' => $imageTag,
1156  'configuration' => $parameterConfiguration,
1157  'expected' => [],
1158  'expectedParams' => $expectedParameters,
1159  ];
1160 
1161  $stdWrapConfiguration = $defaultConfiguration;
1162  $stdWrapConfiguration['stdWrap.'] = [
1163  'append' => 'TEXT',
1164  'append.' => [
1165  'value' => 'appendedString',
1166  ],
1167  ];
1168  yield 'stdWrap is called upon the whole content.' => [
1169  'content' => $imageTag,
1170  'configuration' => $stdWrapConfiguration,
1171  'expected' => [
1172  'appendedString' => true,
1173  ],
1174  ];
1175  }
1176 
1177  #[DataProvider('imageLinkWrapWrapsTheContentAsConfiguredDataProvider')]
1178  #[Test]
1179  public function ‪imageLinkWrapWrapsTheContentAsConfigured(string $content, array $configuration, array $expected, array $expectedParams = []): void
1180  {
1181  $this->importCSVDataSet(__DIR__ . '/DataSet/FileReferences.csv');
1182  $fileReferenceData = [
1183  'uid' => 1,
1184  'uid_local' => 1,
1185  'crop' => '{"default":{"cropArea":{"x":0,"y":0,"width":1,"height":1},"selectedRatio":"NaN","focusArea":null}}',
1186  ];
1187  $fileReference = new ‪FileReference($fileReferenceData);
1188  $typoScriptFrontendController = GeneralUtility::makeInstance(TypoScriptFrontendController::class);
1189  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class, $typoScriptFrontendController);
1190  $subject->setCurrentFile($fileReference);
1191  $typoScript = new ‪FrontendTypoScript(new ‪RootNode(), []);
1192  $typoScript->setConfigArray([]);
1193  $request = $this->‪getPreparedRequest()->withAttribute('frontend.typoscript', $typoScript);
1194  $subject->setRequest($request);
1195  $result = $subject->imageLinkWrap($content, $fileReference, $configuration);
1196 
1197  foreach ($expected as $expectedString => $shouldContain) {
1198  if ($shouldContain) {
1199  self::assertStringContainsString($expectedString, $result);
1200  } else {
1201  self::assertStringNotContainsString($expectedString, $result);
1202  }
1203  }
1204 
1205  if ($expectedParams !== []) {
1206  preg_match('@href="(.*)"@U', $result, $matches);
1207  self::assertArrayHasKey(1, $matches);
1208  ‪$url = parse_url(html_entity_decode($matches[1]));
1209  parse_str(‪$url['query'], $queryResult);
1210  $base64_string = implode('', $queryResult['parameters']);
1211  $base64_decoded = base64_decode($base64_string);
1212  $jsonDecodedArray = json_decode($base64_decoded, true);
1213  self::assertSame($expectedParams, $jsonDecodedArray);
1214  }
1215  }
1216 
1217  #[Test]
1219  {
1220  $this->importCSVDataSet(__DIR__ . '/DataSet/FileReferences.csv');
1221  $fileReferenceData = [
1222  'uid' => 1,
1223  'uid_local' => 1,
1224  'crop' => '{"default":{"cropArea":{"x":0,"y":0,"width":0.5,"height":0.5},"selectedRatio":"NaN","focusArea":null}}',
1225  ];
1226  $fileReference = new ‪FileReference($fileReferenceData);
1227 
1228  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1229  $result = $subject->getImgResource($fileReference, []);
1230 
1231  $expectedWidth = 512;
1232  $expectedHeight = 341;
1233 
1234  self::assertEquals($expectedWidth, $result->getWidth());
1235  self::assertEquals($expectedHeight, $result->getHeight());
1236  }
1237 
1238  #[Test]
1240  {
1241  $afterContentObjectRendererInitializedEvent = null;
1242 
1244  $container = $this->get('service_container');
1245  $container->set(
1246  'after-content-object-renderer-initialized-listener',
1247  static function (‪AfterContentObjectRendererInitializedEvent $event) use (&$afterContentObjectRendererInitializedEvent) {
1248  $afterContentObjectRendererInitializedEvent = $event;
1249  $afterContentObjectRendererInitializedEvent->‪getContentObjectRenderer()->data['foo'] = 'baz';
1250  $afterContentObjectRendererInitializedEvent->getContentObjectRenderer()->setCurrentVal('foo current val');
1251  }
1252  );
1253 
1254  $eventListener = $container->get(ListenerProvider::class);
1255  $eventListener->addListener(AfterContentObjectRendererInitializedEvent::class, 'after-content-object-renderer-initialized-listener');
1256 
1257  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1258  $subject->start(['foo' => 'bar'], 'aTable');
1259 
1260  self::assertInstanceOf(AfterContentObjectRendererInitializedEvent::class, $afterContentObjectRendererInitializedEvent);
1261 
1262  $modifiedContentObjectRenderer = $afterContentObjectRendererInitializedEvent->getContentObjectRenderer();
1263 
1264  self::assertEquals($subject, $modifiedContentObjectRenderer);
1265  self::assertEquals(
1266  [
1267  'foo' => 'baz',
1268  $modifiedContentObjectRenderer->currentValKey => 'foo current val',
1269  ],
1270  $modifiedContentObjectRenderer->data
1271  );
1272  self::assertEquals('aTable', $modifiedContentObjectRenderer->getCurrentTable());
1273  self::assertEquals('foo current val', $modifiedContentObjectRenderer->getCurrentVal());
1274  }
1275 
1276  #[Test]
1277  public function ‪afterGetDataResolvedEventIsCalled(): void
1278  {
1279  $afterGetDataResolvedEvent = null;
1280 
1282  $container = $this->get('service_container');
1283  $container->set(
1284  'after-get-data-resolved-listener',
1285  static function (‪AfterGetDataResolvedEvent $event) use (&$afterGetDataResolvedEvent) {
1286  $afterGetDataResolvedEvent = $event;
1287  $event->‪setResult('modified-result');
1288  }
1289  );
1290 
1291  $eventListener = $container->get(ListenerProvider::class);
1292  $eventListener->addListener(AfterGetDataResolvedEvent::class, 'after-get-data-resolved-listener');
1293 
1294  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1295  $subject->start(['foo' => 'bar'], 'aTable');
1296  $subject->getData('field:title', ['title' => 'title']);
1297 
1298  self::assertInstanceOf(AfterGetDataResolvedEvent::class, $afterGetDataResolvedEvent);
1299  self::assertEquals($subject, $afterGetDataResolvedEvent->getContentObjectRenderer());
1300  self::assertEquals('field:title', $afterGetDataResolvedEvent->getParameterString());
1301  self::assertEquals(['title' => 'title'], $afterGetDataResolvedEvent->getAlternativeFieldArray());
1302  self::assertEquals('modified-result', $afterGetDataResolvedEvent->getResult());
1303  }
1304 
1305  #[Test]
1306  public function ‪afterImageResourceResolvedEventIsCalled(): void
1307  {
1308  $afterImageResourceResolvedEvent = null;
1309 
1311  $container = $this->get('service_container');
1312  $container->set(
1313  'after-image-resource-resolved-listener',
1314  static function (‪AfterImageResourceResolvedEvent $event) use (&$afterImageResourceResolvedEvent) {
1315  $afterImageResourceResolvedEvent = $event;
1316  $modifiedImageResource = $afterImageResourceResolvedEvent->‪getImageResource()?->withPublicUrl('modified-public-url');
1317  $event->‪setImageResource($modifiedImageResource);
1318  }
1319  );
1320 
1321  $eventListener = $container->get(ListenerProvider::class);
1322  $eventListener->addListener(AfterImageResourceResolvedEvent::class, 'after-image-resource-resolved-listener');
1323 
1324  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1325  $subject->start(['foo' => 'bar'], 'aTable');
1326  $subject->getImgResource('GIFBUILDER', ['foo' => 'bar']);
1327 
1328  self::assertInstanceOf(AfterImageResourceResolvedEvent::class, $afterImageResourceResolvedEvent);
1329  self::assertEquals('GIFBUILDER', $afterImageResourceResolvedEvent->getFile());
1330  self::assertEquals(['foo' => 'bar'], $afterImageResourceResolvedEvent->getFileArray());
1331  self::assertEquals('modified-public-url', $afterImageResourceResolvedEvent->getImageResource()->getPublicUrl());
1332  }
1333 
1334  #[Test]
1335  public function ‪enhanceStdWrapEventIsCalled(): void
1336  {
1337  $wrap = '<h1>|</h1>';
1338  $content = 'modified content';
1339  $enhanceStdWrapEvent = null;
1340 
1342  $container = $this->get('service_container');
1343  $container->set(
1344  'enhance-stdWrap-listener',
1345  static function (‪EnhanceStdWrapEvent $event) use (&$enhanceStdWrapEvent, $content) {
1346  $enhanceStdWrapEvent = $event;
1347  $event->‪setContent($content);
1348  }
1349  );
1350 
1351  $eventListener = $container->get(ListenerProvider::class);
1352  $eventListener->addListener(EnhanceStdWrapEvent::class, 'enhance-stdWrap-listener');
1353 
1354  $subject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
1355  $result = $subject->stdWrap('Test', ['wrap' => $wrap]);
1356 
1357  self::assertInstanceOf(EnhanceStdWrapEvent::class, $enhanceStdWrapEvent);
1358  self::assertEquals($content, $result);
1359  self::assertEquals($content, $enhanceStdWrapEvent->getContent());
1360  self::assertEquals($wrap, $enhanceStdWrapEvent->getConfiguration()['wrap']);
1361  self::assertEquals($subject, $enhanceStdWrapEvent->getContentObjectRenderer());
1362  }
1363 }
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typoLinkProperlyEncodesLinkResult
‪typoLinkProperlyEncodesLinkResult(string $linkText, array $configuration, string $expectedResult)
Definition: ContentObjectRendererTest.php:876
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksAndUrls
‪typolinkReturnsCorrectLinksAndUrls(string $linkText, array $configuration, string $expectedResult)
Definition: ContentObjectRendererTest.php:559
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\enhanceStdWrapEventIsCalled
‪enhanceStdWrapEventIsCalled()
Definition: ContentObjectRendererTest.php:1334
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\imageLinkWrapWrapsTheContentAsConfiguredDataProvider
‪static imageLinkWrapWrapsTheContentAsConfiguredDataProvider()
Definition: ContentObjectRendererTest.php:1012
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinkForSpamEncryptedEmailsDataProvider
‪static typolinkReturnsCorrectLinkForSpamEncryptedEmailsDataProvider()
Definition: ContentObjectRendererTest.php:566
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typoLinkProperlyEncodesLinkResultDataProvider
‪static typoLinkProperlyEncodesLinkResultDataProvider()
Definition: ContentObjectRendererTest.php:805
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\checkIfReturnsExpectedValues
‪checkIfReturnsExpectedValues(array $configuration, bool $expected)
Definition: ContentObjectRendererTest.php:1003
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getLibParseFunc
‪getLibParseFunc()
Definition: ContentObjectRendererTest.php:928
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait
Definition: SiteBasedTestTrait.php:37
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterContentObjectRendererInitializedEvent
Definition: AfterContentObjectRendererInitializedEvent.php:26
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\afterContentObjectRendererInitializedEventIsCalled
‪afterContentObjectRendererInitializedEventIsCalled()
Definition: ContentObjectRendererTest.php:1238
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:50
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent
Definition: AfterImageResourceResolvedEvent.php:29
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:37
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:96
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\setUp
‪setUp()
Definition: ContentObjectRendererTest.php:61
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getImgResourceRespectsFileReferenceObjectCropData
‪getImgResourceRespectsFileReferenceObjectCropData()
Definition: ContentObjectRendererTest.php:1217
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildErrorHandlingConfiguration
‪buildErrorHandlingConfiguration(string $handler, array $codes)
Definition: SiteBasedTestTrait.php:150
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\afterGetDataResolvedEventIsCalled
‪afterGetDataResolvedEventIsCalled()
Definition: ContentObjectRendererTest.php:1276
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\$pathsToProvideInTestInstance
‪array $pathsToProvideInTestInstance
Definition: ContentObjectRendererTest.php:59
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\afterImageResourceResolvedEventIsCalled
‪afterImageResourceResolvedEventIsCalled()
Definition: ContentObjectRendererTest.php:1305
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQuery
‪getQuery(string $table, array $conf, array $expected)
Definition: ContentObjectRendererTest.php:203
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent\getImageResource
‪getImageResource()
Definition: AfterImageResourceResolvedEvent.php:46
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinkForSpamEncryptedEmails
‪typolinkReturnsCorrectLinkForSpamEncryptedEmails(array $tsfeConfig, string $linkText, string $parameter, string $expected)
Definition: ContentObjectRendererTest.php:664
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getPreparedRequest
‪getPreparedRequest()
Definition: ContentObjectRendererTest.php:77
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typoLinkLogsErrorIfNoLinkResolvingIsPossible
‪typoLinkLogsErrorIfNoLinkResolvingIsPossible()
Definition: ContentObjectRendererTest.php:269
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest
Definition: ContentObjectRendererTest.php:53
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\LANGUAGE_PRESETS
‪const LANGUAGE_PRESETS
Definition: ContentObjectRendererTest.php:55
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksForFilesWithAbsRefPrefix
‪typolinkReturnsCorrectLinksForFilesWithAbsRefPrefix(string $linkText, array $configuration, string $absRefPrefix, string $expectedResult)
Definition: ContentObjectRendererTest.php:795
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typoLinkReturnsOnlyLinkTextIfNoLinkResolvingIsPossible
‪typoLinkReturnsOnlyLinkTextIfNoLinkResolvingIsPossible()
Definition: ContentObjectRendererTest.php:256
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\libParseFuncProperlyKeepsTagsUnescaped
‪libParseFuncProperlyKeepsTagsUnescaped()
Definition: ContentObjectRendererTest.php:897
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksDataProvider
‪static typolinkReturnsCorrectLinksDataProvider()
Definition: ContentObjectRendererTest.php:283
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\checkIfReturnsExpectedValuesDataProvider
‪static checkIfReturnsExpectedValuesDataProvider()
Definition: ContentObjectRendererTest.php:980
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:82
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildDefaultLanguageConfiguration
‪buildDefaultLanguageConfiguration(string $identifier, string $base)
Definition: SiteBasedTestTrait.php:106
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\TypoScript\AST\Node\RootNode
Definition: RootNode.php:26
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkLinkResultIsInstanceOfLinkResultInterface
‪typolinkLinkResultIsInstanceOfLinkResultInterface()
Definition: ContentObjectRendererTest.php:247
‪TYPO3\CMS\Frontend\ContentObject\Event\EnhanceStdWrapEvent\setContent
‪setContent(string $content)
Definition: EnhanceStdWrapEvent.php:48
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterGetDataResolvedEvent\setResult
‪setResult(mixed $result)
Definition: AfterGetDataResolvedEvent.php:39
‪TYPO3\CMS\Core\Log\Logger
Definition: Logger.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:102
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\searchWhereWithTooShortSearchWordWillReturnValidWhereStatement
‪searchWhereWithTooShortSearchWordWillReturnValidWhereStatement()
Definition: ContentObjectRendererTest.php:884
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\getQueryDataProvider
‪static getQueryDataProvider()
Definition: ContentObjectRendererTest.php:83
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\imageLinkWrapWrapsTheContentAsConfigured
‪imageLinkWrapWrapsTheContentAsConfigured(string $content, array $configuration, array $expected, array $expectedParams=[])
Definition: ContentObjectRendererTest.php:1178
‪TYPO3\CMS\Frontend\ContentObject\Event\EnhanceStdWrapEvent
Definition: EnhanceStdWrapEvent.php:36
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject
Definition: ContentContentObjectTest.php:18
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\TypoScript\FrontendTypoScript
Definition: FrontendTypoScript.php:29
‪TYPO3\CMS\Frontend\Tests\Functional\ContentObject\ContentObjectRendererTest\typolinkReturnsCorrectLinksForFilesWithAbsRefPrefixDataProvider
‪static typolinkReturnsCorrectLinksForFilesWithAbsRefPrefixDataProvider()
Definition: ContentObjectRendererTest.php:674
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterGetDataResolvedEvent
Definition: AfterGetDataResolvedEvent.php:26
‪TYPO3\CMS\Core\EventDispatcher\ListenerProvider
Definition: ListenerProvider.php:30
‪TYPO3\CMS\Core\Http\NormalizedParams\createFromRequest
‪static static createFromRequest(ServerRequestInterface $request, array $systemConfiguration=null)
Definition: NormalizedParams.php:840
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent\setImageResource
‪setImageResource(?ImageResource $imageResource)
Definition: AfterImageResourceResolvedEvent.php:51
‪TYPO3\CMS\Core\Resource\Exception\InvalidPathException
Definition: InvalidPathException.php:23
‪TYPO3\CMS\Frontend\Page\PageInformation
Definition: PageInformation.php:28
‪TYPO3\CMS\Core\Http\NormalizedParams
Definition: NormalizedParams.php:38
‪TYPO3\CMS\Frontend\ContentObject\Event\AfterContentObjectRendererInitializedEvent\getContentObjectRenderer
‪getContentObjectRenderer()
Definition: AfterContentObjectRendererInitializedEvent.php:31
‪TYPO3\CMS\Core\Database\Platform\PlatformHelper
Definition: PlatformHelper.php:26