‪TYPO3CMS  9.5
SlugLinkGeneratorTest.php
Go to the documentation of this file.
1 <?php
2 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 
21 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
22 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
23 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
24 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
25 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
26 
31 {
35  private ‪$siteTitle = 'A Company that Manufactures Everything Inc';
36 
41 
42  public static function ‪setUpBeforeClass()
43  {
44  parent::setUpBeforeClass();
45  static::initializeDatabaseSnapshot();
46  }
47 
48  public static function ‪tearDownAfterClass()
49  {
50  static::destroyDatabaseSnapshot();
51  parent::tearDownAfterClass();
52  }
53 
54  protected function ‪setUp()
55  {
56  parent::setUp();
57 
58  // these settings are forwarded to the frontend sub-request as well
59  $this->internalRequestContext = (new InternalRequestContext())
60  ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
61 
63  'acme-com',
64  $this->‪buildSiteConfiguration(1000, 'https://acme.com/'),
65  [
66  $this->‪buildDefaultLanguageConfiguration('EN', 'https://acme.us/'),
67  $this->‪buildLanguageConfiguration('FR', 'https://acme.fr/', ['EN']),
68  $this->‪buildLanguageConfiguration('FR-CA', 'https://acme.ca/', ['FR', 'EN']),
69  ]
70  );
72  'products-acme-com',
73  $this->‪buildSiteConfiguration(1300, 'https://products.acme.com/')
74  );
76  'blog-acme-com',
77  $this->‪buildSiteConfiguration(2000, 'https://blog.acme.com/')
78  );
80  'john-blog-acme-com',
81  $this->‪buildSiteConfiguration(2110, 'https://blog.acme.com/john/')
82  );
84  'jane-blog-acme-com',
85  $this->‪buildSiteConfiguration(2120, 'https://blog.acme.com/jane/')
86  );
87 
88  $this->withDatabaseSnapshot(function () {
89  $this->‪setUpDatabase();
90  });
91  }
92 
93  protected function ‪setUpDatabase()
94  {
95  $backendUser = $this->setUpBackendUserFromFixture(1);
97 
98  $scenarioFile = __DIR__ . '/Fixtures/SlugScenario.yaml';
99  $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
100  $writer = DataHandlerWriter::withBackendUser($backendUser);
101  $writer->invokeFactory($factory);
102  static::failIfArrayIsNotEmpty(
103  $writer->getErrors()
104  );
105 
106  $this->setUpFrontendRootPage(
107  1000,
108  [
109  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
110  ],
111  [
112  'title' => 'ACME Root',
113  'sitetitle' => $this->siteTitle,
114  ]
115  );
116  $this->setUpFrontendRootPage(
117  2000,
118  [
119  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
120  ],
121  [
122  'title' => 'ACME Blog',
123  'sitetitle' => $this->siteTitle,
124  ]
125  );
126  }
127 
128  protected function ‪tearDown()
129  {
130  unset($this->internalRequestContext);
131  parent::tearDown();
132  }
133 
137  public function ‪linkIsGeneratedDataProvider(): array
138  {
139  $instructions = [
140  // acme.com -> acme.com (same site)
141  ['https://acme.us/', 1100, 1000, '/'],
142  ['https://acme.us/', 1100, 1100, '/welcome'],
143  ['https://acme.us/', 1100, 1200, '/features'],
144  ['https://acme.us/', 1100, 1210, '/features/frontend-editing'],
145  ['https://acme.us/', 1100, 404, '/404'],
146  // acme.com -> products.acme.com (nested sub-site)
147  ['https://acme.us/', 1100, 1300, 'https://products.acme.com/products'],
148  ['https://acme.us/', 1100, 1310, 'https://products.acme.com/products/planets'],
149  // acme.com -> blog.acme.com (different site)
150  ['https://acme.us/', 1100, 2000, 'https://blog.acme.com/'],
151  ['https://acme.us/', 1100, 2100, 'https://blog.acme.com/authors'],
152  ['https://acme.us/', 1100, 2110, 'https://blog.acme.com/john/john'],
153  ['https://acme.us/', 1100, 2111, 'https://blog.acme.com/john/about-john'],
154  // blog.acme.com -> acme.com (different site)
155  ['https://blog.acme.com/', 2100, 1000, 'https://acme.us/'],
156  ['https://blog.acme.com/', 2100, 1100, 'https://acme.us/welcome'],
157  ['https://blog.acme.com/', 2100, 1200, 'https://acme.us/features'],
158  ['https://blog.acme.com/', 2100, 1210, 'https://acme.us/features/frontend-editing'],
159  ['https://blog.acme.com/', 2100, 404, 'https://acme.us/404'],
160  // blog.acme.com -> products.acme.com (different sub-site)
161  ['https://blog.acme.com/', 2100, 1300, 'https://products.acme.com/products'],
162  ['https://blog.acme.com/', 2100, 1310, 'https://products.acme.com/products/planets'],
163  ];
164 
165  return $this->keysFromTemplate(
166  $instructions,
167  '%2$d->%3$d'
168  );
169  }
170 
180  public function ‪linkIsGenerated(string $hostPrefix, int $sourcePageId, int $targetPageId, string $expectation)
181  {
182  $response = $this->executeFrontendRequest(
183  (new InternalRequest($hostPrefix))
184  ->withPageId($sourcePageId)
185  ->withInstructions([
186  $this->createTypoLinkUrlInstruction([
187  'parameter' => $targetPageId,
188  ])
189  ]),
190  $this->internalRequestContext
191  );
192 
193  static::assertSame($expectation, (string)$response->getBody());
194  }
195 
199  public function ‪linkIsGeneratedFromMountPointDataProvider(): array
200  {
201  $instructions = [
202  // acme.com -> acme.com (same site)
203  ['https://acme.us/', [7100, 1700], 7110, 1000, '/'],
204  ['https://acme.us/', [7100, 1700], 7110, 1100, '/welcome'],
205  ['https://acme.us/', [7100, 1700], 7110, 1200, '/features'],
206  ['https://acme.us/', [7100, 1700], 7110, 1210, '/features/frontend-editing'],
207  ['https://acme.us/', [7100, 1700], 7110, 404, '/404'],
208  // acme.com -> products.acme.com (nested sub-site)
209  ['https://acme.us/', [7100, 1700], 7110, 1300, 'https://products.acme.com/products'],
210  ['https://acme.us/', [7100, 1700], 7110, 1310, 'https://products.acme.com/products/planets'],
211  // acme.com -> blog.acme.com (different site)
212  ['https://acme.us/', [7100, 1700], 7110, 2000, 'https://blog.acme.com/'],
213  ['https://acme.us/', [7100, 1700], 7110, 2100, 'https://blog.acme.com/authors'],
214  ['https://acme.us/', [7100, 1700], 7110, 2110, 'https://blog.acme.com/john/john'],
215  ['https://acme.us/', [7100, 1700], 7110, 2111, 'https://blog.acme.com/john/about-john'],
216  // blog.acme.com -> acme.com (different site)
217  ['https://blog.acme.com/', [7100, 2700], 7110, 1000, 'https://acme.us/'],
218  ['https://blog.acme.com/', [7100, 2700], 7110, 1100, 'https://acme.us/welcome'],
219  ['https://blog.acme.com/', [7100, 2700], 7110, 1200, 'https://acme.us/features'],
220  ['https://blog.acme.com/', [7100, 2700], 7110, 1210, 'https://acme.us/features/frontend-editing'],
221  ['https://blog.acme.com/', [7100, 2700], 7110, 404, 'https://acme.us/404'],
222  // blog.acme.com -> products.acme.com (different sub-site)
223  ['https://blog.acme.com/', [7100, 2700], 7110, 1300, 'https://products.acme.com/products'],
224  ['https://blog.acme.com/', [7100, 2700], 7110, 1310, 'https://products.acme.com/products/planets'],
225  ];
226 
227  return $this->keysFromTemplate(
228  $instructions,
229  '%3$d->%4$d (mount:%2$s)',
230  function (array $items) {
231  array_splice(
232  $items,
233  1,
234  1,
235  [implode('->', $items[1])]
236  );
237  return $items;
238  }
239  );
240  }
241 
252  public function ‪linkIsGeneratedFromMountPoint(string $hostPrefix, array $pageMount, int $sourcePageId, int $targetPageId, string $expectation)
253  {
254  $response = $this->executeFrontendRequest(
255  (new InternalRequest($hostPrefix))
256  ->withMountPoint(...$pageMount)
257  ->withPageId($sourcePageId)
258  ->withInstructions([
259  $this->createTypoLinkUrlInstruction([
260  'parameter' => $targetPageId,
261  ])
262  ]),
263  $this->internalRequestContext
264  );
265 
266  static::assertSame($expectation, (string)$response->getBody());
267  }
268 
272  public function ‪linkIsGeneratedForLanguageDataProvider(): array
273  {
274  $instructions = [
275  // acme.com -> acme.com (same site)
276  ['https://acme.us/', 1100, 1100, 0, '/welcome'],
277  ['https://acme.us/', 1100, 1100, 1, 'https://acme.fr/bienvenue'],
278  ['https://acme.us/', 1100, 1100, 2, 'https://acme.ca/bienvenue'],
279  ['https://acme.us/', 1100, 1101, 0, 'https://acme.fr/bienvenue'],
280  ['https://acme.us/', 1100, 1102, 0, 'https://acme.ca/bienvenue'],
281  // acme.com -> products.acme.com (nested sub-site)
282  ['https://acme.us/', 1100, 1300, 0, 'https://products.acme.com/products'],
283  ['https://acme.us/', 1100, 1310, 0, 'https://products.acme.com/products/planets'],
284  // acme.com -> products.acme.com (nested sub-site, l18n_cfg=1)
285  ['https://acme.us/', 1100, 1410, 0, ''],
286  ['https://acme.us/', 1100, 1410, 1, 'https://acme.fr/acme-dans-votre-region/groupes'],
287  ['https://acme.us/', 1100, 1410, 2, 'https://acme.ca/acme-dans-votre-quebec/groupes'],
288  ['https://acme.us/', 1100, 1411, 0, 'https://acme.fr/acme-dans-votre-region/groupes'],
289  ['https://acme.us/', 1100, 1412, 0, 'https://acme.ca/acme-dans-votre-quebec/groupes'],
290  // acme.com -> archive (outside site)
291  ['https://acme.us/', 1100, 3100, 0, '/index.php?id=3100&L=0'],
292  ['https://acme.us/', 1100, 3100, 1, '/index.php?id=3100&L=1'],
293  ['https://acme.us/', 1100, 3100, 2, '/index.php?id=3100&L=2'],
294  ['https://acme.us/', 1100, 3101, 0, '/index.php?id=3100&L=1'],
295  ['https://acme.us/', 1100, 3102, 0, '/index.php?id=3100&L=2'],
296  // blog.acme.com -> acme.com (different site)
297  ['https://blog.acme.com/', 2100, 1100, 0, 'https://acme.us/welcome'],
298  ['https://blog.acme.com/', 2100, 1100, 1, 'https://acme.fr/bienvenue'],
299  ['https://blog.acme.com/', 2100, 1100, 2, 'https://acme.ca/bienvenue'],
300  ['https://blog.acme.com/', 2100, 1101, 0, 'https://acme.fr/bienvenue'],
301  ['https://blog.acme.com/', 2100, 1102, 0, 'https://acme.ca/bienvenue'],
302  // blog.acme.com -> archive (outside site)
303  ['https://blog.acme.com/', 2100, 3100, 0, '/index.php?id=3100&L=0'],
304  ['https://blog.acme.com/', 2100, 3100, 1, '/index.php?id=3100&L=1'],
305  ['https://blog.acme.com/', 2100, 3100, 2, '/index.php?id=3100&L=2'],
306  ['https://blog.acme.com/', 2100, 3101, 0, '/index.php?id=3100&L=1'],
307  ['https://blog.acme.com/', 2100, 3102, 0, '/index.php?id=3100&L=2'],
308  // blog.acme.com -> products.acme.com (different sub-site)
309  ['https://blog.acme.com/', 2100, 1300, 0, 'https://products.acme.com/products'],
310  ['https://blog.acme.com/', 2100, 1310, 0, 'https://products.acme.com/products/planets'],
311  ];
312 
313  return $this->keysFromTemplate(
314  $instructions,
315  '%2$d->%3$d (lang:%4$d)'
316  );
317  }
318 
329  public function ‪linkIsGeneratedForLanguageWithLanguageProperty(string $hostPrefix, int $sourcePageId, int $targetPageId, int $targetLanguageId, string $expectation)
330  {
331  $response = $this->executeFrontendRequest(
332  (new InternalRequest($hostPrefix))
333  ->withPageId($sourcePageId)
334  ->withInstructions([
335  $this->createTypoLinkUrlInstruction([
336  'parameter' => $targetPageId,
337  'language' => $targetLanguageId,
338  ])
339  ]),
340  $this->internalRequestContext
341  );
342 
343  static::assertSame($expectation, (string)$response->getBody());
344  }
345 
356  public function ‪linkIsGeneratedForLanguageWithLegacyProperty(string $hostPrefix, int $sourcePageId, int $targetPageId, int $targetLanguageId, string $expectation)
357  {
358  $response = $this->executeFrontendRequest(
359  (new InternalRequest($hostPrefix))
360  ->withPageId($sourcePageId)
361  ->withInstructions([
362  $this->createTypoLinkUrlInstruction([
363  'parameter' => $targetPageId,
364  'additionalParams' => '&L=' . $targetLanguageId,
365  ])
366  ]),
367  $this->internalRequestContext
368  );
369 
370  static::assertSame($expectation, (string)$response->getBody());
371  }
372 
377  {
378  $instructions = [
379  // acme.com -> acme.com (same site)
380  ['https://acme.us/', 1100, 1000, '/?testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
381  ['https://acme.us/', 1100, 1100, '/welcome?testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
382  ['https://acme.us/', 1100, 1200, '/features?testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
383  ['https://acme.us/', 1100, 1210, '/features/frontend-editing?testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
384  ['https://acme.us/', 1100, 404, '/404?testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
385  // acme.com -> products.acme.com (nested sub-site)
386  ['https://acme.us/', 1100, 1300, 'https://products.acme.com/products?testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
387  ['https://acme.us/', 1100, 1310, 'https://products.acme.com/products/planets?testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
388  // acme.com -> blog.acme.com (different site)
389  ['https://acme.us/', 1100, 2000, 'https://blog.acme.com/?testing%5Bvalue%5D=1&cHash=a14da633e46dba71640cb85226cd12c5'],
390  ['https://acme.us/', 1100, 2100, 'https://blog.acme.com/authors?testing%5Bvalue%5D=1&cHash=d23d74cb50383f8788a9930ec8ba679f'],
391  ['https://acme.us/', 1100, 2110, 'https://blog.acme.com/john/john?testing%5Bvalue%5D=1&cHash=bf25eea89f44a9a79dabdca98f38a432'],
392  ['https://acme.us/', 1100, 2111, 'https://blog.acme.com/john/about-john?testing%5Bvalue%5D=1&cHash=42dbaeb9172b6b1ca23b49941e194db2'],
393  // blog.acme.com -> acme.com (different site)
394  ['https://blog.acme.com/', 2100, 1000, 'https://acme.us/?testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
395  ['https://blog.acme.com/', 2100, 1100, 'https://acme.us/welcome?testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
396  ['https://blog.acme.com/', 2100, 1200, 'https://acme.us/features?testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
397  ['https://blog.acme.com/', 2100, 1210, 'https://acme.us/features/frontend-editing?testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
398  ['https://blog.acme.com/', 2100, 404, 'https://acme.us/404?testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
399  // blog.acme.com -> products.acme.com (different sub-site)
400  ['https://blog.acme.com/', 2100, 1300, 'https://products.acme.com/products?testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
401  ['https://blog.acme.com/', 2100, 1310, 'https://products.acme.com/products/planets?testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
402  ];
403 
404  return $this->keysFromTemplate(
405  $instructions,
406  '%2$d->%3$d'
407  );
408  }
409 
419  public function ‪linkIsGeneratedWithQueryParameters(string $hostPrefix, int $sourcePageId, int $targetPageId, string $expectation)
420  {
421  $response = $this->executeFrontendRequest(
422  (new InternalRequest($hostPrefix))
423  ->withPageId($sourcePageId)
424  ->withInstructions([
425  $this->createTypoLinkUrlInstruction([
426  'parameter' => $targetPageId,
427  'additionalParams' => '&testing[value]=1',
428  'useCacheHash' => 1,
429  ])
430  ]),
431  $this->internalRequestContext
432  );
433 
434  static::assertSame($expectation, (string)$response->getBody());
435  }
436 
440  public function ‪linkIsGeneratedForRestrictedPageDataProvider(): array
441  {
442  $instructions = [
443  ['https://acme.us/', 1100, 1510, 0, ''],
444  // ['https://acme.us/', 1100, 1511, 0, ''], // @todo Fails, not expanded to sub-pages
445  ['https://acme.us/', 1100, 1512, 0, ''],
446  ['https://acme.us/', 1100, 1515, 0, ''],
447  ['https://acme.us/', 1100, 1520, 0, ''],
448  // ['https://acme.us/', 1100, 1521, 0, ''], // @todo Fails, not expanded to sub-pages
449  //
450  ['https://acme.us/', 1100, 1510, 1, '/my-acme/whitepapers'],
451  ['https://acme.us/', 1100, 1511, 1, '/my-acme/whitepapers/products'],
452  ['https://acme.us/', 1100, 1512, 1, '/my-acme/whitepapers/solutions'],
453  ['https://acme.us/', 1100, 1515, 1, ''],
454  ['https://acme.us/', 1100, 1520, 1, ''],
455  // ['https://acme.us/', 1100, 1521, 1, ''], // @todo Fails, not expanded to sub-pages
456  //
457  ['https://acme.us/', 1100, 1510, 2, '/my-acme/whitepapers'],
458  ['https://acme.us/', 1100, 1511, 2, '/my-acme/whitepapers/products'],
459  ['https://acme.us/', 1100, 1512, 2, ''],
460  ['https://acme.us/', 1100, 1515, 2, '/my-acme/whitepapers/research'],
461  ['https://acme.us/', 1100, 1520, 2, '/my-acme/forecasts'],
462  ['https://acme.us/', 1100, 1521, 2, '/my-acme/forecasts/current-year'],
463  //
464  ['https://acme.us/', 1100, 1510, 3, '/my-acme/whitepapers'],
465  ['https://acme.us/', 1100, 1511, 3, '/my-acme/whitepapers/products'],
466  ['https://acme.us/', 1100, 1512, 3, '/my-acme/whitepapers/solutions'],
467  ['https://acme.us/', 1100, 1515, 3, '/my-acme/whitepapers/research'],
468  ['https://acme.us/', 1100, 1520, 3, '/my-acme/forecasts'],
469  ['https://acme.us/', 1100, 1521, 3, '/my-acme/forecasts/current-year'],
470  ];
471 
472  return $this->keysFromTemplate(
473  $instructions,
474  '%2$d->%3$d (user:%4$d)'
475  );
476  }
477 
488  public function ‪linkIsGeneratedForRestrictedPage(string $hostPrefix, int $sourcePageId, int $targetPageId, int $frontendUserId, string $expectation)
489  {
490  $response = $this->executeFrontendRequest(
491  (new InternalRequest($hostPrefix))
492  ->withPageId($sourcePageId)
493  ->withInstructions([
494  $this->createTypoLinkUrlInstruction([
495  'parameter' => $targetPageId,
496  ])
497  ]),
498  $this->internalRequestContext
499  ->withFrontendUserId($frontendUserId)
500  );
501 
502  static::assertSame($expectation, (string)$response->getBody());
503  }
504 
509  {
510  $instructions = [
511  // no frontend user given
512  ['https://acme.us/', 1100, 1510, 1500, 0, '/my-acme?pageId=1510&cHash=119c4870e323bb7e8c9fae2941726b0d'],
513  // ['https://acme.us/', 1100, 1511, 1500, 0, '/my-acme?pageId=1511'], // @todo Fails, not expanded to sub-pages
514  ['https://acme.us/', 1100, 1512, 1500, 0, '/my-acme?pageId=1512&cHash=0ced3db0fd4aae0019a99f59cfa58cb0'],
515  ['https://acme.us/', 1100, 1515, 1500, 0, '/my-acme?pageId=1515&cHash=176f16b31d2c731347d411861d8b06dc'],
516  ['https://acme.us/', 1100, 1520, 1500, 0, '/my-acme?pageId=1520&cHash=253d3dccd4794c4a9473226f683bc36a'],
517  // ['https://acme.us/', 1100, 1521, 1500, 0, '/my-acme?pageId=1521'], // @todo Fails, not expanded to sub-pages
518  // frontend user 1
519  ['https://acme.us/', 1100, 1510, 1500, 1, '/my-acme/whitepapers'],
520  ['https://acme.us/', 1100, 1511, 1500, 1, '/my-acme/whitepapers/products'],
521  ['https://acme.us/', 1100, 1512, 1500, 1, '/my-acme/whitepapers/solutions'],
522  ['https://acme.us/', 1100, 1515, 1500, 1, '/my-acme?pageId=1515&cHash=176f16b31d2c731347d411861d8b06dc'],
523  ['https://acme.us/', 1100, 1520, 1500, 1, '/my-acme?pageId=1520&cHash=253d3dccd4794c4a9473226f683bc36a'],
524  // ['https://acme.us/', 1100, 1521, 1500, 1, '/my-acme?pageId=1521'], // @todo Fails, not expanded to sub-pages
525  // frontend user 2
526  ['https://acme.us/', 1100, 1510, 1500, 2, '/my-acme/whitepapers'],
527  ['https://acme.us/', 1100, 1511, 1500, 2, '/my-acme/whitepapers/products'],
528  ['https://acme.us/', 1100, 1512, 1500, 2, '/my-acme?pageId=1512&cHash=0ced3db0fd4aae0019a99f59cfa58cb0'],
529  ['https://acme.us/', 1100, 1515, 1500, 2, '/my-acme/whitepapers/research'],
530  ['https://acme.us/', 1100, 1520, 1500, 2, '/my-acme/forecasts'],
531  ['https://acme.us/', 1100, 1521, 1500, 2, '/my-acme/forecasts/current-year'],
532  // frontend user 3
533  ['https://acme.us/', 1100, 1510, 1500, 3, '/my-acme/whitepapers'],
534  ['https://acme.us/', 1100, 1511, 1500, 3, '/my-acme/whitepapers/products'],
535  ['https://acme.us/', 1100, 1512, 1500, 3, '/my-acme/whitepapers/solutions'],
536  ['https://acme.us/', 1100, 1515, 1500, 3, '/my-acme/whitepapers/research'],
537  ['https://acme.us/', 1100, 1520, 1500, 3, '/my-acme/forecasts'],
538  ['https://acme.us/', 1100, 1521, 1500, 3, '/my-acme/forecasts/current-year'],
539  ];
540 
541  return $this->keysFromTemplate(
542  $instructions,
543  '%2$d->%3$d (via: %4$d, user:%5$d)'
544  );
545  }
546 
558  public function ‪linkIsGeneratedForRestrictedPageUsingLoginPage(string $hostPrefix, int $sourcePageId, int $targetPageId, int $loginPageId, int $frontendUserId, string $expectation)
559  {
560  $response = $this->executeFrontendRequest(
561  (new InternalRequest($hostPrefix))
562  ->withPageId($sourcePageId)
563  ->withInstructions([
564  (new TypoScriptInstruction(TemplateService::class))
565  ->withTypoScript([
566  'config.' => [
567  'typolinkLinkAccessRestrictedPages' => $loginPageId,
568  'typolinkLinkAccessRestrictedPages_addParams' => '&pageId=###PAGE_ID###'
569  ],
570  ]),
571  $this->createTypoLinkUrlInstruction([
572  'parameter' => $targetPageId,
573  ])
574  ]),
575  $this->internalRequestContext
576  ->withFrontendUserId($frontendUserId)
577  );
578 
579  static::assertSame($expectation, (string)$response->getBody());
580  }
581 
586  {
587  $instructions = [
588  // default language (0)
589  ['https://acme.us/', 1100, 1510, 0, '/my-acme/whitepapers'],
590  ['https://acme.us/', 1100, 1512, 0, '/my-acme/whitepapers/solutions'],
591  ['https://acme.us/', 1100, 1515, 0, '/my-acme/whitepapers/research'],
592  // french language (1)
593  ['https://acme.fr/', 1100, 1510, 1, '/my-acme/papiersblanc'],
594  ['https://acme.fr/', 1100, 1512, 1, '/my-acme/papiersblanc/la-solutions'],
595  ['https://acme.fr/', 1100, 1515, 1, '/my-acme/papiersblanc/recherche'],
596  // canadian french language (2)
597  ['https://acme.ca/', 1100, 1510, 2, '/my-acme-ca/papiersblanc'],
598  ['https://acme.ca/', 1100, 1512, 2, '/my-acme-ca/papiersblanc/la-solutions'],
599  ['https://acme.ca/', 1100, 1515, 2, '/my-acme-ca/papiersblanc/recherche'],
600  ];
601 
602  return $this->keysFromTemplate(
603  $instructions,
604  '%2$d->%3$d (language: %4$d)'
605  );
606  }
607 
618  public function ‪linkIsGeneratedForRestrictedPageForGuestsUsingTypolinkLinkAccessRestrictedPages(string $hostPrefix, int $sourcePageId, int $targetPageId, int $languageId, string $expectation)
619  {
620  $response = $this->executeFrontendRequest(
621  (new InternalRequest($hostPrefix))
622  ->withPageId($sourcePageId)
623  ->withInstructions([
624  (new TypoScriptInstruction(TemplateService::class))
625  ->withTypoScript([
626  'config.' => [
627  'typolinkLinkAccessRestrictedPages' => 'NONE',
628  ],
629  ]),
630  $this->createTypoLinkUrlInstruction([
631  'parameter' => $targetPageId,
632  ])
633  ]),
634  $this->internalRequestContext
635  );
636 
637  self::assertSame($expectation, (string)$response->getBody());
638  }
639 
643  public function ‪linkIsGeneratedForPageVersionDataProvider(): array
644  {
645  $instructions = [
646  // acme.com -> acme.com (same site): link to changed page
647  ['https://acme.us/', 1100, 1100, false, 1, '/welcome-modified'],
648  ['https://acme.us/', 1100, 1100, true, 1, '/welcome-modified'],
649  ['https://acme.us/', 1100, 1100, false, 0, '/welcome'],
650  ['https://acme.us/', 1100, 1100, true, 0, '/index.php?id=acme-first'], // @todo this is wrong, link should be empty
651  // acme.com -> acme.com (same site): link to new page
652  ['https://acme.us/', 1100, 1950, false, 1, '/bye'],
653  ['https://acme.us/', 1100, 1950, true, 1, '/bye'],
654  ['https://acme.us/', 1100, 1950, false, 0, ''],
655  ['https://acme.us/', 1100, 1950, true, 0, '/index.php?id={targetPageId}'], // @todo this is wrong, link should be empty
656  // blog.acme.com -> acme.com (different site): link to changed page
657  ['https://blog.acme.com/', 2100, 1100, true, 1, 'https://acme.us/welcome-modified'],
658  ['https://blog.acme.com/', 2100, 1100, false, 1, 'https://acme.us/welcome-modified'],
659  ['https://blog.acme.com/', 2100, 1100, false, 0, 'https://acme.us/welcome'],
660  ['https://blog.acme.com/', 2100, 1100, true, 0, '/index.php?id=acme-first'], // @todo this is wrong, link should be empty
661  // blog.acme.com -> acme.com (different site): link to new page
662  ['https://blog.acme.com/', 2100, 1950, false, 1, 'https://acme.us/bye'],
663  ['https://blog.acme.com/', 2100, 1950, true, 1, 'https://acme.us/bye'],
664  ['https://blog.acme.com/', 2100, 1950, false, 0, ''],
665  ['https://blog.acme.com/', 2100, 1950, true, 0, '/index.php?id={targetPageId}'], // @todo this is wrong, link should be empty
666  ];
667 
668  return $this->keysFromTemplate(
669  $instructions,
670  '%2$d->%3$d (resolve:%4$d, be_user:%5$d)'
671  );
672  }
673 
685  public function ‪linkIsGeneratedForPageVersion(string $hostPrefix, int $sourcePageId, int $targetPageId, bool $resolveVersion, int $backendUserId, string $expectation)
686  {
687  $workspaceId = 1;
688  if ($resolveVersion) {
690  $workspaceId,
691  'pages',
692  $targetPageId,
693  'uid'
694  )['uid'] ?? null;
695  }
696 
697  $response = $this->executeFrontendRequest(
698  (new InternalRequest($hostPrefix))
699  ->withPageId($sourcePageId)
700  ->withInstructions([
701  $this->createTypoLinkUrlInstruction([
702  'parameter' => $targetPageId,
703  ])
704  ]),
705  $this->internalRequestContext
706  ->withWorkspaceId($backendUserId !== 0 ? $workspaceId : 0)
707  ->withBackendUserId($backendUserId)
708  );
709 
710  $expectation = str_replace(
711  ['{targetPageId}'],
712  [$targetPageId],
713  $expectation
714  );
715 
716  static::assertSame($expectation, (string)$response->getBody());
717  }
718 
722  public function ‪hierarchicalMenuIsGeneratedDataProvider(): array
723  {
724  return [
725  'ACME Inc' => [
726  'https://acme.us/',
727  1100,
728  [
729  ['title' => 'EN: Welcome', 'link' => '/welcome'],
730  [
731  'title' => 'EN: Features',
732  'link' => '/features',
733  'children' => [
734  [
735  'title' => 'EN: Frontend Editing',
736  'link' => '/features/frontend-editing',
737  ],
738  ],
739  ],
740  [
741  'title' => 'EN: Products',
742  'link' => 'https://products.acme.com/products',
743  'children' => [
744  [
745  'title' => 'EN: Planets',
746  'link' => 'https://products.acme.com/products/planets',
747  ],
748  [
749  'title' => 'EN: Spaceships',
750  'link' => 'https://products.acme.com/products/spaceships',
751  ],
752  [
753  'title' => 'EN: Dark Matter',
754  'link' => 'https://products.acme.com/products/dark-matter',
755  ],
756  ],
757  ],
758  ['title' => 'EN: ACME in your Region', 'link' => '/acme-in-your-region'],
759  ['title' => 'Internal', 'link' => '/my-acme'],
760  ['title' => 'About us', 'link' => '/about'],
761  [
762  'title' => 'Announcements & News',
763  'link' => '/news',
764  'children' => [
765  [
766  'title' => 'Markets',
767  'link' => '/news/common/markets',
768  ],
769  [
770  'title' => 'Products',
771  'link' => '/news/common/products',
772  ],
773  [
774  'title' => 'Partners',
775  'link' => '/news/common/partners',
776  ],
777  ],
778  ],
779  ['title' => 'Page not found', 'link' => '/404'],
780  ['title' => 'Our Blog', 'link' => 'https://blog.acme.com/authors'],
781  ]
782  ],
783  'ACME Blog' => [
784  'https://blog.acme.com/',
785  2100,
786  [
787  [
788  'title' => 'Authors',
789  'link' => '/authors',
790  'children' => [
791  [
792  'title' => 'John Doe',
793  'link' => 'https://blog.acme.com/john/john',
794  ],
795  [
796  'title' => 'Jane Doe',
797  'link' => 'https://blog.acme.com/jane/jane',
798  ],
799  ],
800  ],
801  1 =>
802  [
803  'title' => 'Announcements & News',
804  'link' => '/news',
805  'children' => [
806  [
807  'title' => 'Markets',
808  'link' => '/news/common/markets',
809  ],
810  [
811  'title' => 'Products',
812  'link' => '/news/common/products',
813  ],
814  [
815  'title' => 'Partners',
816  'link' => '/news/common/partners',
817  ],
818  ],
819  ],
820  ['title' => 'ACME Inc', 'link' => 'https://acme.us/welcome'],
821  ]
822  ]
823  ];
824  }
825 
834  public function ‪hierarchicalMenuIsGenerated(string $hostPrefix, int $sourcePageId, array $expectation)
835  {
836  $response = $this->executeFrontendRequest(
837  (new InternalRequest($hostPrefix))
838  ->withPageId($sourcePageId)
839  ->withInstructions([
840  $this->createHierarchicalMenuProcessorInstruction([
841  'levels' => 2,
842  'entryLevel' => 0,
843  'expandAll' => 1,
844  'includeSpacer' => 1,
845  'titleField' => 'title',
846  ])
847  ]),
848  $this->internalRequestContext
849  );
850 
851  $json = json_decode((string)$response->getBody(), true);
852  $json = $this->filterMenu($json);
853 
854  static::assertSame($expectation, $json);
855  }
856 
860  public function ‪languageMenuIsGeneratedDataProvider(): array
861  {
862  return [
863  'ACME Inc (EN)' => [
864  'https://acme.us/',
865  1100,
866  [
867  ['title' => 'English', 'link' => '/welcome'],
868  ['title' => 'French', 'link' => 'https://acme.fr/bienvenue'],
869  ['title' => 'Franco-Canadian', 'link' => 'https://acme.ca/bienvenue'],
870  ]
871  ],
872  'ACME Inc (FR)' => [
873  'https://acme.fr/',
874  1100,
875  [
876  ['title' => 'English', 'link' => 'https://acme.us/welcome'],
877  ['title' => 'French', 'link' => '/bienvenue'],
878  ['title' => 'Franco-Canadian', 'link' => 'https://acme.ca/bienvenue'],
879  ]
880  ],
881  'ACME Inc (FR-CA)' => [
882  'https://acme.ca/',
883  1100,
884  [
885  ['title' => 'English', 'link' => 'https://acme.us/welcome'],
886  ['title' => 'French', 'link' => 'https://acme.fr/bienvenue'],
887  ['title' => 'Franco-Canadian', 'link' => '/bienvenue'],
888  ]
889  ],
890  'ACME Blog' => [
891  'https://blog.acme.com/',
892  2100,
893  [
894  ['title' => 'Default', 'link' => '/authors']
895  ]
896  ]
897  ];
898  }
899 
908  public function ‪languageMenuIsGenerated(string $hostPrefix, int $sourcePageId, array $expectation)
909  {
910  $response = $this->executeFrontendRequest(
911  (new InternalRequest($hostPrefix))
912  ->withPageId($sourcePageId)
913  ->withInstructions([
914  $this->createLanguageMenuProcessorInstruction([
915  'languages' => 'auto',
916  ])
917  ]),
918  $this->internalRequestContext
919  );
920 
921  $json = json_decode((string)$response->getBody(), true);
922  $json = $this->filterMenu($json);
923 
924  static::assertSame($expectation, $json);
925  }
926 }
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildLanguageConfiguration
‪array buildLanguageConfiguration(string $identifier, string $base, array $fallbackIdentifiers=[], string $fallbackType=null)
Definition: SiteBasedTestTrait.php:140
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:56
‪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:122
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪TYPO3\CMS\Backend\Utility\BackendUtility\getWorkspaceVersionOfRecord
‪static array bool getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *')
Definition: BackendUtility.php:4166
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:50
‪TYPO3\CMS\Frontend\Tests\Functional\SiteHandling
Definition: AbstractTestCase.php:3
‪TYPO3\CMS\Core\Core\Bootstrap
Definition: Bootstrap.php:50
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪array buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:107
‪TYPO3\CMS\Core\Core\Bootstrap\initializeLanguageObject
‪static Bootstrap null initializeLanguageObject()
Definition: Bootstrap.php:986