‪TYPO3CMS  10.4
SlugLinkGeneratorTest.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 
23 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
24 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
25 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
26 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
27 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
28 
33 {
37  private ‪$siteTitle = 'A Company that Manufactures Everything Inc';
38 
43 
44  public static function ‪setUpBeforeClass(): void
45  {
46  parent::setUpBeforeClass();
47  static::initializeDatabaseSnapshot();
48  }
49 
50  public static function ‪tearDownAfterClass(): void
51  {
52  static::destroyDatabaseSnapshot();
53  parent::tearDownAfterClass();
54  }
55 
56  protected function ‪setUp(): void
57  {
58  parent::setUp();
59 
60  // these settings are forwarded to the frontend sub-request as well
61  $this->internalRequestContext = (new InternalRequestContext())
62  ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
63 
65  'acme-com',
66  $this->‪buildSiteConfiguration(1000, 'https://acme.com/'),
67  [
68  $this->‪buildDefaultLanguageConfiguration('EN', 'https://acme.us/'),
69  $this->‪buildLanguageConfiguration('FR', 'https://acme.fr/', ['EN']),
70  $this->‪buildLanguageConfiguration('FR-CA', 'https://acme.ca/', ['FR', 'EN']),
71  ]
72  );
74  'products-acme-com',
75  $this->‪buildSiteConfiguration(1300, 'https://products.acme.com/')
76  );
78  'blog-acme-com',
79  $this->‪buildSiteConfiguration(2000, 'https://blog.acme.com/')
80  );
82  'john-blog-acme-com',
83  $this->‪buildSiteConfiguration(2110, 'https://blog.acme.com/john/')
84  );
86  'jane-blog-acme-com',
87  $this->‪buildSiteConfiguration(2120, 'https://blog.acme.com/jane/')
88  );
90  'archive-acme-com',
91  $this->‪buildSiteConfiguration(3000, 'https://archive.acme.com/'),
92  [
93  $this->‪buildDefaultLanguageConfiguration('EN', '/'),
94  $this->‪buildLanguageConfiguration('FR', 'https://archive.acme.com/fr/', ['EN']),
95  $this->‪buildLanguageConfiguration('FR-CA', 'https://archive.acme.com/ca/', ['FR', 'EN'])
96  ]
97  );
99  'common-collection',
100  $this->‪buildSiteConfiguration(7000, 'https://common.acme.com/')
101  );
102 
103  $this->withDatabaseSnapshot(function () {
104  $this->‪setUpDatabase();
105  });
106  }
107 
108  protected function ‪setUpDatabase()
109  {
110  $backendUser = $this->setUpBackendUserFromFixture(1);
112 
113  $scenarioFile = __DIR__ . '/Fixtures/SlugScenario.yaml';
114  $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
115  $writer = DataHandlerWriter::withBackendUser($backendUser);
116  $writer->invokeFactory($factory);
117  static::failIfArrayIsNotEmpty(
118  $writer->getErrors()
119  );
120 
121  $this->setUpFrontendRootPage(
122  1000,
123  [
124  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
125  ],
126  [
127  'title' => 'ACME Root',
128  'sitetitle' => $this->siteTitle,
129  ]
130  );
131  $this->setUpFrontendRootPage(
132  2000,
133  [
134  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
135  ],
136  [
137  'title' => 'ACME Blog',
138  'sitetitle' => $this->siteTitle,
139  ]
140  );
141  }
142 
143  protected function ‪tearDown(): void
144  {
145  unset($this->internalRequestContext);
146  parent::tearDown();
147  }
148 
152  public function ‪linkIsGeneratedDataProvider(): array
153  {
154  $instructions = [
155  // acme.com -> acme.com (same site)
156  ['https://acme.us/', 1100, 1000, '/'],
157  ['https://acme.us/', 1100, 1100, '/welcome'],
158  ['https://acme.us/', 1100, 1200, '/features'],
159  ['https://acme.us/', 1100, 1210, '/features/frontend-editing/'],
160  ['https://acme.us/', 1100, 404, '/404'],
161  // acme.com -> products.acme.com (nested sub-site)
162  ['https://acme.us/', 1100, 1300, 'https://products.acme.com/products'],
163  ['https://acme.us/', 1100, 1310, 'https://products.acme.com/products/planets'],
164  // acme.com -> blog.acme.com (different site)
165  ['https://acme.us/', 1100, 2000, 'https://blog.acme.com/'],
166  ['https://acme.us/', 1100, 2100, 'https://blog.acme.com/authors'],
167  ['https://acme.us/', 1100, 2110, 'https://blog.acme.com/john/john'],
168  ['https://acme.us/', 1100, 2111, 'https://blog.acme.com/john/about-john'],
169  // blog.acme.com -> acme.com (different site)
170  ['https://blog.acme.com/', 2100, 1000, 'https://acme.us/'],
171  ['https://blog.acme.com/', 2100, 1100, 'https://acme.us/welcome'],
172  ['https://blog.acme.com/', 2100, 1200, 'https://acme.us/features'],
173  ['https://blog.acme.com/', 2100, 1210, 'https://acme.us/features/frontend-editing/'],
174  ['https://blog.acme.com/', 2100, 404, 'https://acme.us/404'],
175  // blog.acme.com -> products.acme.com (different sub-site)
176  ['https://blog.acme.com/', 2100, 1300, 'https://products.acme.com/products'],
177  ['https://blog.acme.com/', 2100, 1310, 'https://products.acme.com/products/planets'],
178  ];
179 
180  return $this->keysFromTemplate(
181  $instructions,
182  '%2$d->%3$d'
183  );
184  }
185 
195  public function ‪linkIsGenerated(string $hostPrefix, int $sourcePageId, int $targetPageId, string $expectation)
196  {
197  $response = $this->executeFrontendRequest(
198  (new InternalRequest($hostPrefix))
199  ->withPageId($sourcePageId)
200  ->withInstructions([
201  $this->createTypoLinkUrlInstruction([
202  'parameter' => $targetPageId,
203  ])
204  ]),
205  $this->internalRequestContext
206  );
207 
208  self::assertSame($expectation, (string)$response->getBody());
209  }
210 
214  public function ‪linkIsGeneratedFromMountPointDataProvider(): array
215  {
216  $instructions = [
217  // acme.com -> acme.com (same site)
218  ['https://acme.us/', [7100, 1700], 7110, 1000, '/'],
219  ['https://acme.us/', [7100, 1700], 7110, 1100, '/welcome'],
220  ['https://acme.us/', [7100, 1700], 7110, 1200, '/features'],
221  ['https://acme.us/', [7100, 1700], 7110, 1210, '/features/frontend-editing/'],
222  ['https://acme.us/', [7100, 1700], 7110, 404, '/404'],
223  // acme.com -> products.acme.com (nested sub-site)
224  ['https://acme.us/', [7100, 1700], 7110, 1300, 'https://products.acme.com/products'],
225  ['https://acme.us/', [7100, 1700], 7110, 1310, 'https://products.acme.com/products/planets'],
226  // acme.com -> blog.acme.com (different site)
227  ['https://acme.us/', [7100, 1700], 7110, 2000, 'https://blog.acme.com/'],
228  ['https://acme.us/', [7100, 1700], 7110, 2100, 'https://blog.acme.com/authors'],
229  ['https://acme.us/', [7100, 1700], 7110, 2110, 'https://blog.acme.com/john/john'],
230  ['https://acme.us/', [7100, 1700], 7110, 2111, 'https://blog.acme.com/john/about-john'],
231  // blog.acme.com -> acme.com (different site)
232  ['https://blog.acme.com/', [7100, 2700], 7110, 1000, 'https://acme.us/'],
233  ['https://blog.acme.com/', [7100, 2700], 7110, 1100, 'https://acme.us/welcome'],
234  ['https://blog.acme.com/', [7100, 2700], 7110, 1200, 'https://acme.us/features'],
235  ['https://blog.acme.com/', [7100, 2700], 7110, 1210, 'https://acme.us/features/frontend-editing/'],
236  ['https://blog.acme.com/', [7100, 2700], 7110, 404, 'https://acme.us/404'],
237  // blog.acme.com -> products.acme.com (different sub-site)
238  ['https://blog.acme.com/', [7100, 2700], 7110, 1300, 'https://products.acme.com/products'],
239  ['https://blog.acme.com/', [7100, 2700], 7110, 1310, 'https://products.acme.com/products/planets'],
240  ];
241 
242  return $this->keysFromTemplate(
243  $instructions,
244  '%3$d->%4$d (mount:%2$s)',
245  function (array $items) {
246  array_splice(
247  $items,
248  1,
249  1,
250  [implode('->', $items[1])]
251  );
252  return $items;
253  }
254  );
255  }
256 
267  public function ‪linkIsGeneratedFromMountPoint(string $hostPrefix, array $pageMount, int $sourcePageId, int $targetPageId, string $expectation)
268  {
269  $response = $this->executeFrontendRequest(
270  (new InternalRequest($hostPrefix))
271  ->withMountPoint(...$pageMount)
272  ->withPageId($sourcePageId)
273  ->withInstructions([
274  $this->createTypoLinkUrlInstruction([
275  'parameter' => $targetPageId,
276  ])
277  ]),
278  $this->internalRequestContext
279  );
280 
281  self::assertSame($expectation, (string)$response->getBody());
282  }
283 
287  public function ‪linkIsGeneratedForLanguageDataProvider(): array
288  {
289  $instructions = [
290  // acme.com -> acme.com (same site)
291  ['https://acme.us/', 1100, 1100, 0, '/welcome'],
292  ['https://acme.us/', 1100, 1100, 1, 'https://acme.fr/bienvenue'],
293  ['https://acme.us/', 1100, 1100, 2, 'https://acme.ca/bienvenue'],
294  ['https://acme.us/', 1100, 1101, 0, 'https://acme.fr/bienvenue'],
295  ['https://acme.us/', 1100, 1102, 0, 'https://acme.ca/bienvenue'],
296  // acme.com -> products.acme.com (nested sub-site)
297  ['https://acme.us/', 1100, 1300, 0, 'https://products.acme.com/products'],
298  ['https://acme.us/', 1100, 1310, 0, 'https://products.acme.com/products/planets'],
299  // acme.com -> products.acme.com (nested sub-site, l18n_cfg=1)
300  ['https://acme.us/', 1100, 1410, 0, ''],
301  ['https://acme.us/', 1100, 1410, 1, 'https://acme.fr/acme-dans-votre-region/groupes'],
302  ['https://acme.us/', 1100, 1410, 2, 'https://acme.ca/acme-dans-votre-quebec/groupes'],
303  ['https://acme.us/', 1100, 1411, 0, 'https://acme.fr/acme-dans-votre-region/groupes'],
304  ['https://acme.us/', 1100, 1412, 0, 'https://acme.ca/acme-dans-votre-quebec/groupes'],
305  // acme.com -> archive (outside site)
306  ['https://acme.us/', 1100, 3100, 0, 'https://archive.acme.com/statistics'],
307  ['https://acme.us/', 1100, 3100, 1, 'https://archive.acme.com/fr/statistics'],
308  ['https://acme.us/', 1100, 3100, 2, 'https://archive.acme.com/ca/statistics'],
309  ['https://acme.us/', 1100, 3101, 0, 'https://archive.acme.com/fr/statistics'],
310  ['https://acme.us/', 1100, 3102, 0, 'https://archive.acme.com/ca/statistics'],
311  // blog.acme.com -> acme.com (different site)
312  ['https://blog.acme.com/', 2100, 1100, 0, 'https://acme.us/welcome'],
313  ['https://blog.acme.com/', 2100, 1100, 1, 'https://acme.fr/bienvenue'],
314  ['https://blog.acme.com/', 2100, 1100, 2, 'https://acme.ca/bienvenue'],
315  ['https://blog.acme.com/', 2100, 1101, 0, 'https://acme.fr/bienvenue'],
316  ['https://blog.acme.com/', 2100, 1102, 0, 'https://acme.ca/bienvenue'],
317  // blog.acme.com -> archive (outside site)
318  ['https://blog.acme.com/', 2100, 3100, 0, 'https://archive.acme.com/statistics'],
319  ['https://blog.acme.com/', 2100, 3100, 1, 'https://archive.acme.com/fr/statistics'],
320  ['https://blog.acme.com/', 2100, 3100, 2, 'https://archive.acme.com/ca/statistics'],
321  ['https://blog.acme.com/', 2100, 3101, 0, 'https://archive.acme.com/fr/statistics'],
322  ['https://blog.acme.com/', 2100, 3102, 0, 'https://archive.acme.com/ca/statistics'],
323  // blog.acme.com -> products.acme.com (different sub-site)
324  ['https://blog.acme.com/', 2100, 1300, 0, 'https://products.acme.com/products'],
325  ['https://blog.acme.com/', 2100, 1310, 0, 'https://products.acme.com/products/planets'],
326  ];
327 
328  return $this->keysFromTemplate(
329  $instructions,
330  '%2$d->%3$d (lang:%4$d)'
331  );
332  }
333 
344  public function ‪linkIsGeneratedForLanguageWithLanguageProperty(string $hostPrefix, int $sourcePageId, int $targetPageId, int $targetLanguageId, string $expectation)
345  {
346  $response = $this->executeFrontendRequest(
347  (new InternalRequest($hostPrefix))
348  ->withPageId($sourcePageId)
349  ->withInstructions([
350  $this->createTypoLinkUrlInstruction([
351  'parameter' => $targetPageId,
352  'language' => $targetLanguageId,
353  ])
354  ]),
355  $this->internalRequestContext
356  );
357 
358  self::assertSame($expectation, (string)$response->getBody());
359  }
360 
365  {
366  $instructions = [
367  // acme.com -> acme.com (same site)
368  ['https://acme.us/', 1100, 1000, '/?testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
369  ['https://acme.us/', 1100, 1100, '/welcome?testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
370  ['https://acme.us/', 1100, 1200, '/features?testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
371  ['https://acme.us/', 1100, 1210, '/features/frontend-editing/?testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
372  ['https://acme.us/', 1100, 404, '/404?testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
373  // acme.com -> products.acme.com (nested sub-site)
374  ['https://acme.us/', 1100, 1300, 'https://products.acme.com/products?testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
375  ['https://acme.us/', 1100, 1310, 'https://products.acme.com/products/planets?testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
376  // acme.com -> blog.acme.com (different site)
377  ['https://acme.us/', 1100, 2000, 'https://blog.acme.com/?testing%5Bvalue%5D=1&cHash=a14da633e46dba71640cb85226cd12c5'],
378  ['https://acme.us/', 1100, 2100, 'https://blog.acme.com/authors?testing%5Bvalue%5D=1&cHash=d23d74cb50383f8788a9930ec8ba679f'],
379  ['https://acme.us/', 1100, 2110, 'https://blog.acme.com/john/john?testing%5Bvalue%5D=1&cHash=bf25eea89f44a9a79dabdca98f38a432'],
380  ['https://acme.us/', 1100, 2111, 'https://blog.acme.com/john/about-john?testing%5Bvalue%5D=1&cHash=42dbaeb9172b6b1ca23b49941e194db2'],
381  // blog.acme.com -> acme.com (different site)
382  ['https://blog.acme.com/', 2100, 1000, 'https://acme.us/?testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
383  ['https://blog.acme.com/', 2100, 1100, 'https://acme.us/welcome?testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
384  ['https://blog.acme.com/', 2100, 1200, 'https://acme.us/features?testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
385  ['https://blog.acme.com/', 2100, 1210, 'https://acme.us/features/frontend-editing/?testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
386  ['https://blog.acme.com/', 2100, 404, 'https://acme.us/404?testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
387  // blog.acme.com -> products.acme.com (different sub-site)
388  ['https://blog.acme.com/', 2100, 1300, 'https://products.acme.com/products?testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
389  ['https://blog.acme.com/', 2100, 1310, 'https://products.acme.com/products/planets?testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
390  ];
391 
392  return $this->keysFromTemplate(
393  $instructions,
394  '%2$d->%3$d'
395  );
396  }
397 
407  public function ‪linkIsGeneratedWithQueryParameters(string $hostPrefix, int $sourcePageId, int $targetPageId, string $expectation)
408  {
409  $response = $this->executeFrontendRequest(
410  (new InternalRequest($hostPrefix))
411  ->withPageId($sourcePageId)
412  ->withInstructions([
413  $this->createTypoLinkUrlInstruction([
414  'parameter' => $targetPageId,
415  'additionalParams' => '&testing[value]=1'
416  ])
417  ]),
418  $this->internalRequestContext
419  );
420 
421  self::assertSame($expectation, (string)$response->getBody());
422  }
423 
427  public function ‪linkIsGeneratedForRestrictedPageDataProvider(): array
428  {
429  $instructions = [
430  ['https://acme.us/', 1100, 1510, 0, ''],
431  // ['https://acme.us/', 1100, 1511, 0, ''], // @todo Fails, not expanded to sub-pages
432  ['https://acme.us/', 1100, 1512, 0, ''],
433  ['https://acme.us/', 1100, 1515, 0, ''],
434  ['https://acme.us/', 1100, 1520, 0, ''],
435  // ['https://acme.us/', 1100, 1521, 0, ''], // @todo Fails, not expanded to sub-pages
436  //
437  ['https://acme.us/', 1100, 1510, 1, '/my-acme/whitepapers'],
438  ['https://acme.us/', 1100, 1511, 1, '/my-acme/whitepapers/products'],
439  ['https://acme.us/', 1100, 1512, 1, '/my-acme/whitepapers/solutions'],
440  ['https://acme.us/', 1100, 1515, 1, ''],
441  ['https://acme.us/', 1100, 1520, 1, ''],
442  // ['https://acme.us/', 1100, 1521, 1, ''], // @todo Fails, not expanded to sub-pages
443  //
444  ['https://acme.us/', 1100, 1510, 2, '/my-acme/whitepapers'],
445  ['https://acme.us/', 1100, 1511, 2, '/my-acme/whitepapers/products'],
446  ['https://acme.us/', 1100, 1512, 2, ''],
447  ['https://acme.us/', 1100, 1515, 2, '/my-acme/whitepapers/research'],
448  ['https://acme.us/', 1100, 1520, 2, '/my-acme/forecasts'],
449  ['https://acme.us/', 1100, 1521, 2, '/my-acme/forecasts/current-year'],
450  //
451  ['https://acme.us/', 1100, 1510, 3, '/my-acme/whitepapers'],
452  ['https://acme.us/', 1100, 1511, 3, '/my-acme/whitepapers/products'],
453  ['https://acme.us/', 1100, 1512, 3, '/my-acme/whitepapers/solutions'],
454  ['https://acme.us/', 1100, 1515, 3, '/my-acme/whitepapers/research'],
455  ['https://acme.us/', 1100, 1520, 3, '/my-acme/forecasts'],
456  ['https://acme.us/', 1100, 1521, 3, '/my-acme/forecasts/current-year'],
457  ];
458 
459  return $this->keysFromTemplate(
460  $instructions,
461  '%2$d->%3$d (user:%4$d)'
462  );
463  }
464 
475  public function ‪linkIsGeneratedForRestrictedPage(string $hostPrefix, int $sourcePageId, int $targetPageId, int $frontendUserId, string $expectation)
476  {
477  $response = $this->executeFrontendRequest(
478  (new InternalRequest($hostPrefix))
479  ->withPageId($sourcePageId)
480  ->withInstructions([
481  $this->createTypoLinkUrlInstruction([
482  'parameter' => $targetPageId,
483  ])
484  ]),
485  $this->internalRequestContext
486  ->withFrontendUserId($frontendUserId)
487  );
488 
489  self::assertSame($expectation, (string)$response->getBody());
490  }
491 
496  {
497  $instructions = [
498  // no frontend user given
499  ['https://acme.us/', 1100, 1510, 1500, 0, '/my-acme?pageId=1510&cHash=119c4870e323bb7e8c9fae2941726b0d'],
500  // ['https://acme.us/', 1100, 1511, 1500, 0, '/my-acme?pageId=1511'], // @todo Fails, not expanded to sub-pages
501  ['https://acme.us/', 1100, 1512, 1500, 0, '/my-acme?pageId=1512&cHash=0ced3db0fd4aae0019a99f59cfa58cb0'],
502  ['https://acme.us/', 1100, 1515, 1500, 0, '/my-acme?pageId=1515&cHash=176f16b31d2c731347d411861d8b06dc'],
503  ['https://acme.us/', 1100, 1520, 1500, 0, '/my-acme?pageId=1520&cHash=253d3dccd4794c4a9473226f683bc36a'],
504  // ['https://acme.us/', 1100, 1521, 1500, 0, '/my-acme?pageId=1521'], // @todo Fails, not expanded to sub-pages
505  // frontend user 1
506  ['https://acme.us/', 1100, 1510, 1500, 1, '/my-acme/whitepapers'],
507  ['https://acme.us/', 1100, 1511, 1500, 1, '/my-acme/whitepapers/products'],
508  ['https://acme.us/', 1100, 1512, 1500, 1, '/my-acme/whitepapers/solutions'],
509  ['https://acme.us/', 1100, 1515, 1500, 1, '/my-acme?pageId=1515&cHash=176f16b31d2c731347d411861d8b06dc'],
510  ['https://acme.us/', 1100, 1520, 1500, 1, '/my-acme?pageId=1520&cHash=253d3dccd4794c4a9473226f683bc36a'],
511  // ['https://acme.us/', 1100, 1521, 1500, 1, '/my-acme?pageId=1521'], // @todo Fails, not expanded to sub-pages
512  // frontend user 2
513  ['https://acme.us/', 1100, 1510, 1500, 2, '/my-acme/whitepapers'],
514  ['https://acme.us/', 1100, 1511, 1500, 2, '/my-acme/whitepapers/products'],
515  ['https://acme.us/', 1100, 1512, 1500, 2, '/my-acme?pageId=1512&cHash=0ced3db0fd4aae0019a99f59cfa58cb0'],
516  ['https://acme.us/', 1100, 1515, 1500, 2, '/my-acme/whitepapers/research'],
517  ['https://acme.us/', 1100, 1520, 1500, 2, '/my-acme/forecasts'],
518  ['https://acme.us/', 1100, 1521, 1500, 2, '/my-acme/forecasts/current-year'],
519  // frontend user 3
520  ['https://acme.us/', 1100, 1510, 1500, 3, '/my-acme/whitepapers'],
521  ['https://acme.us/', 1100, 1511, 1500, 3, '/my-acme/whitepapers/products'],
522  ['https://acme.us/', 1100, 1512, 1500, 3, '/my-acme/whitepapers/solutions'],
523  ['https://acme.us/', 1100, 1515, 1500, 3, '/my-acme/whitepapers/research'],
524  ['https://acme.us/', 1100, 1520, 1500, 3, '/my-acme/forecasts'],
525  ['https://acme.us/', 1100, 1521, 1500, 3, '/my-acme/forecasts/current-year'],
526  ];
527 
528  return $this->keysFromTemplate(
529  $instructions,
530  '%2$d->%3$d (via: %4$d, user:%5$d)'
531  );
532  }
533 
545  public function ‪linkIsGeneratedForRestrictedPageUsingLoginPage(string $hostPrefix, int $sourcePageId, int $targetPageId, int $loginPageId, int $frontendUserId, string $expectation)
546  {
547  $response = $this->executeFrontendRequest(
548  (new InternalRequest($hostPrefix))
549  ->withPageId($sourcePageId)
550  ->withInstructions([
551  (new TypoScriptInstruction(TemplateService::class))
552  ->withTypoScript([
553  'config.' => [
554  'typolinkLinkAccessRestrictedPages' => $loginPageId,
555  'typolinkLinkAccessRestrictedPages_addParams' => '&pageId=###PAGE_ID###'
556  ],
557  ]),
558  $this->createTypoLinkUrlInstruction([
559  'parameter' => $targetPageId,
560  ])
561  ]),
562  $this->internalRequestContext
563  ->withFrontendUserId($frontendUserId)
564  );
565 
566  self::assertSame($expectation, (string)$response->getBody());
567  }
568 
573  {
574  $instructions = [
575  // default language (0)
576  ['https://acme.us/', 1100, 1510, 0, '/my-acme/whitepapers'],
577  ['https://acme.us/', 1100, 1512, 0, '/my-acme/whitepapers/solutions'],
578  ['https://acme.us/', 1100, 1515, 0, '/my-acme/whitepapers/research'],
579  // french language (1)
580  ['https://acme.fr/', 1100, 1510, 1, '/my-acme/papiersblanc'],
581  ['https://acme.fr/', 1100, 1512, 1, '/my-acme/papiersblanc/la-solutions'],
582  ['https://acme.fr/', 1100, 1515, 1, '/my-acme/papiersblanc/recherche'],
583  // canadian french language (2)
584  ['https://acme.ca/', 1100, 1510, 2, '/my-acme-ca/papiersblanc'],
585  ['https://acme.ca/', 1100, 1512, 2, '/my-acme-ca/papiersblanc/la-solutions'],
586  ['https://acme.ca/', 1100, 1515, 2, '/my-acme-ca/papiersblanc/recherche'],
587  ];
588 
589  return $this->keysFromTemplate(
590  $instructions,
591  '%2$d->%3$d (language: %4$d)'
592  );
593  }
594 
605  public function ‪linkIsGeneratedForRestrictedPageForGuestsUsingTypolinkLinkAccessRestrictedPages(string $hostPrefix, int $sourcePageId, int $targetPageId, int $languageId, string $expectation)
606  {
607  $response = $this->executeFrontendRequest(
608  (new InternalRequest($hostPrefix))
609  ->withPageId($sourcePageId)
610  ->withInstructions([
611  (new TypoScriptInstruction(TemplateService::class))
612  ->withTypoScript([
613  'config.' => [
614  'typolinkLinkAccessRestrictedPages' => 'NONE',
615  ],
616  ]),
617  $this->createTypoLinkUrlInstruction([
618  'parameter' => $targetPageId,
619  ])
620  ]),
621  $this->internalRequestContext
622  );
623 
624  self::assertSame($expectation, (string)$response->getBody());
625  }
626 
630  public function ‪linkIsGeneratedForPageVersionDataProvider(): array
631  {
632  $instructions = [
633  // acme.com -> acme.com (same site): link to changed page
634  ['https://acme.us/', 1100, 1100, false, 1, '/welcome-modified'],
635  ['https://acme.us/', 1100, 1100, true, 1, '/welcome-modified'],
636  ['https://acme.us/', 1100, 1100, false, 0, '/welcome'],
637  ['https://acme.us/', 1100, 1100, true, 0, ''], // @todo link is empty, but should create a link
638  // acme.com -> acme.com (same site): link to new page
639  ['https://acme.us/', 1100, 1950, false, 1, '/bye'],
640  ['https://acme.us/', 1100, 1950, true, 1, '/bye'],
641  ['https://acme.us/', 1100, 1950, false, 0, ''],
642  ['https://acme.us/', 1100, 1950, true, 0, ''], // @todo link is empty, but should create a link
643  // blog.acme.com -> acme.com (different site): link to changed page
644  ['https://blog.acme.com/', 2100, 1100, true, 1, 'https://acme.us/welcome-modified'],
645  ['https://blog.acme.com/', 2100, 1100, false, 1, 'https://acme.us/welcome-modified'],
646  ['https://blog.acme.com/', 2100, 1100, false, 0, 'https://acme.us/welcome'],
647  ['https://blog.acme.com/', 2100, 1100, true, 0, ''], // @todo link is empty, but should create a link
648  // blog.acme.com -> acme.com (different site): link to new page
649  ['https://blog.acme.com/', 2100, 1950, false, 1, 'https://acme.us/bye'],
650  ['https://blog.acme.com/', 2100, 1950, true, 1, 'https://acme.us/bye'],
651  ['https://blog.acme.com/', 2100, 1950, false, 0, ''],
652  ['https://blog.acme.com/', 2100, 1950, true, 0, ''], // @todo link is empty, but should create a link
653  ];
654 
655  return $this->keysFromTemplate(
656  $instructions,
657  '%2$d->%3$d (resolve:%4$d, be_user:%5$d)'
658  );
659  }
660 
672  public function ‪linkIsGeneratedForPageVersion(string $hostPrefix, int $sourcePageId, int $targetPageId, bool $resolveVersion, int $backendUserId, string $expectation)
673  {
674  $workspaceId = 1;
675  if ($resolveVersion) {
677  $workspaceId,
678  'pages',
679  $targetPageId,
680  'uid'
681  )['uid'] ?? null;
682  }
683 
684  $response = $this->executeFrontendRequest(
685  (new InternalRequest($hostPrefix))
686  ->withPageId($sourcePageId)
687  ->withInstructions([
688  $this->createTypoLinkUrlInstruction([
689  'parameter' => $targetPageId,
690  ])
691  ]),
692  $this->internalRequestContext
693  ->withWorkspaceId($backendUserId !== 0 ? $workspaceId : 0)
694  ->withBackendUserId($backendUserId)
695  );
696 
697  $expectation = str_replace(
698  ['{targetPageId}'],
699  [$targetPageId],
700  $expectation
701  );
702 
703  self::assertSame($expectation, (string)$response->getBody());
704  }
705 
709  public function ‪hierarchicalMenuIsGeneratedDataProvider(): array
710  {
711  return [
712  'ACME Inc' => [
713  'https://acme.us/',
714  1100,
715  [
716  ['title' => 'EN: Welcome', 'link' => '/welcome'],
717  [
718  'title' => 'ZH-CN: Welcome Default',
719  // Symfony UrlGenerator, which is used for uri generation, rawurlencodes the url internally.
720  'link' => '/%E7%AE%80-bienvenue',
721  ],
722  [
723  'title' => 'EN: Features',
724  'link' => '/features',
725  'children' => [
726  [
727  'title' => 'EN: Frontend Editing',
728  'link' => '/features/frontend-editing/',
729  ],
730  ],
731  ],
732  [
733  'title' => 'EN: Products',
734  'link' => 'https://products.acme.com/products',
735  'children' => [
736  [
737  'title' => 'EN: Planets',
738  'link' => 'https://products.acme.com/products/planets',
739  ],
740  [
741  'title' => 'EN: Spaceships',
742  'link' => 'https://products.acme.com/products/spaceships',
743  ],
744  [
745  'title' => 'EN: Dark Matter',
746  'link' => 'https://products.acme.com/products/dark-matter',
747  ],
748  ],
749  ],
750  ['title' => 'EN: ACME in your Region', 'link' => '/acme-in-your-region'],
751  ['title' => 'Internal', 'link' => '/my-acme'],
752  ['title' => 'About us', 'link' => '/about'],
753  [
754  'title' => 'Announcements & News',
755  'link' => '/news',
756  'children' => [
757  [
758  'title' => 'Markets',
759  'link' => '/news/common/markets',
760  ],
761  [
762  'title' => 'Products',
763  'link' => '/news/common/products',
764  ],
765  [
766  'title' => 'Partners',
767  'link' => '/news/common/partners',
768  ],
769  ],
770  ],
771  ['title' => 'Page not found', 'link' => '/404'],
772  ['title' => 'Our Blog', 'link' => 'https://blog.acme.com/authors'],
773  ]
774  ],
775  'ACME Blog' => [
776  'https://blog.acme.com/',
777  2100,
778  [
779  [
780  'title' => 'Authors',
781  'link' => '/authors',
782  'children' => [
783  [
784  'title' => 'John Doe',
785  'link' => 'https://blog.acme.com/john/john',
786  ],
787  [
788  'title' => 'Jane Doe',
789  'link' => 'https://blog.acme.com/jane/jane',
790  ],
791  ],
792  ],
793  1 =>
794  [
795  'title' => 'Announcements & News',
796  'link' => '/news',
797  'children' => [
798  [
799  'title' => 'Markets',
800  'link' => '/news/common/markets',
801  ],
802  [
803  'title' => 'Products',
804  'link' => '/news/common/products',
805  ],
806  [
807  'title' => 'Partners',
808  'link' => '/news/common/partners',
809  ],
810  ],
811  ],
812  ['title' => 'ACME Inc', 'link' => 'https://acme.us/welcome'],
813  ]
814  ]
815  ];
816  }
817 
826  public function ‪hierarchicalMenuIsGenerated(string $hostPrefix, int $sourcePageId, array $expectation)
827  {
828  $response = $this->executeFrontendRequest(
829  (new InternalRequest($hostPrefix))
830  ->withPageId($sourcePageId)
831  ->withInstructions([
832  $this->createHierarchicalMenuProcessorInstruction([
833  'levels' => 2,
834  'entryLevel' => 0,
835  'expandAll' => 1,
836  'includeSpacer' => 1,
837  'titleField' => 'title',
838  ])
839  ]),
840  $this->internalRequestContext
841  );
842 
843  $json = json_decode((string)$response->getBody(), true);
844  $json = $this->filterMenu($json);
845 
846  self::assertSame($expectation, $json);
847  }
848 
852  public function ‪languageMenuIsGeneratedDataProvider(): array
853  {
854  return [
855  'ACME Inc (EN)' => [
856  'https://acme.us/',
857  1100,
858  [
859  ['title' => 'English', 'link' => '/welcome'],
860  ['title' => 'French', 'link' => 'https://acme.fr/bienvenue'],
861  ['title' => 'Franco-Canadian', 'link' => 'https://acme.ca/bienvenue'],
862  ]
863  ],
864  'ACME Inc (FR)' => [
865  'https://acme.fr/',
866  1100,
867  [
868  ['title' => 'English', 'link' => 'https://acme.us/welcome'],
869  ['title' => 'French', 'link' => '/bienvenue'],
870  ['title' => 'Franco-Canadian', 'link' => 'https://acme.ca/bienvenue'],
871  ]
872  ],
873  'ACME Inc (FR-CA)' => [
874  'https://acme.ca/',
875  1100,
876  [
877  ['title' => 'English', 'link' => 'https://acme.us/welcome'],
878  ['title' => 'French', 'link' => 'https://acme.fr/bienvenue'],
879  ['title' => 'Franco-Canadian', 'link' => '/bienvenue'],
880  ]
881  ],
882  'ACME Blog' => [
883  'https://blog.acme.com/',
884  2100,
885  [
886  ['title' => 'Default', 'link' => '/authors']
887  ]
888  ]
889  ];
890  }
891 
900  public function ‪languageMenuIsGenerated(string $hostPrefix, int $sourcePageId, array $expectation)
901  {
902  $response = $this->executeFrontendRequest(
903  (new InternalRequest($hostPrefix))
904  ->withPageId($sourcePageId)
905  ->withInstructions([
906  $this->createLanguageMenuProcessorInstruction([
907  'languages' => 'auto',
908  ])
909  ]),
910  $this->internalRequestContext
911  );
912 
913  $json = json_decode((string)$response->getBody(), true);
914  $json = $this->filterMenu($json);
915 
916  self::assertSame($expectation, $json);
917  }
918 }
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildLanguageConfiguration
‪array buildLanguageConfiguration(string $identifier, string $base, array $fallbackIdentifiers=[], string $fallbackType=null)
Definition: SiteBasedTestTrait.php:142
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:58
‪TYPO3\CMS\Frontend\Tests\Functional\SiteHandling\AbstractTestCase
Definition: AbstractTestCase.php:29
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildDefaultLanguageConfiguration
‪array buildDefaultLanguageConfiguration(string $identifier, string $base)
Definition: SiteBasedTestTrait.php:124
‪TYPO3\CMS\Core\Core\Bootstrap\initializeLanguageObject
‪static initializeLanguageObject()
Definition: Bootstrap.php:617
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Backend\Utility\BackendUtility\getWorkspaceVersionOfRecord
‪static array bool getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *')
Definition: BackendUtility.php:3705
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:46
‪TYPO3\CMS\Frontend\Tests\Functional\SiteHandling
Definition: AbstractTestCase.php:18
‪TYPO3\CMS\Core\Core\Bootstrap
Definition: Bootstrap.php:66
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪array buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:109