cbeb0cdf03d986f76b725415aa083c52a844f567
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / EnhancerLinkGeneratorTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Tests\Functional\SiteHandling;
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
18 use TYPO3\CMS\Core\Core\Bootstrap;
19 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
20 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
21 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
22 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
23
24 /**
25 * Test case for frontend requests having site handling configured using enhancers.
26 */
27 class EnhancerLinkGeneratorTest extends AbstractTestCase
28 {
29 /**
30 * @var string
31 */
32 private $siteTitle = 'A Company that Manufactures Everything Inc';
33
34 /**
35 * @var InternalRequestContext
36 */
37 private $internalRequestContext;
38
39 public static function setUpBeforeClass()
40 {
41 parent::setUpBeforeClass();
42 static::initializeDatabaseSnapshot();
43 }
44
45 public static function tearDownAfterClass()
46 {
47 static::destroyDatabaseSnapshot();
48 parent::tearDownAfterClass();
49 }
50
51 protected function setUp()
52 {
53 parent::setUp();
54
55 // these settings are forwarded to the frontend sub-request as well
56 $this->internalRequestContext = (new InternalRequestContext())
57 ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
58
59 $this->writeSiteConfiguration(
60 'acme-com',
61 $this->buildSiteConfiguration(1000, 'https://acme.com/'),
62 [
63 $this->buildDefaultLanguageConfiguration('EN', 'https://acme.us/'),
64 $this->buildLanguageConfiguration('FR', 'https://acme.fr/', ['EN']),
65 $this->buildLanguageConfiguration('FR-CA', 'https://acme.ca/', ['FR', 'EN']),
66 ]
67 );
68
69 $this->withDatabaseSnapshot(function () {
70 $this->setUpDatabase();
71 });
72 }
73
74 protected function setUpDatabase()
75 {
76 $backendUser = $this->setUpBackendUserFromFixture(1);
77 Bootstrap::initializeLanguageObject();
78
79 $scenarioFile = __DIR__ . '/Fixtures/SlugScenario.yaml';
80 $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
81 $writer = DataHandlerWriter::withBackendUser($backendUser);
82 $writer->invokeFactory($factory);
83 static::failIfArrayIsNotEmpty(
84 $writer->getErrors()
85 );
86
87 $this->setUpFrontendRootPage(
88 1000,
89 [
90 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
91 ],
92 [
93 'title' => 'ACME Root',
94 'sitetitle' => $this->siteTitle,
95 ]
96 );
97 }
98
99 protected function tearDown()
100 {
101 unset($this->internalRequestContext);
102 parent::tearDown();
103 }
104
105 /**
106 * @param array $aspect
107 * @param array $languages
108 * @param array $enhancers
109 * @param string $variableName
110 * @param string $templateSuffix
111 * @return array
112 */
113 protected function createDataSet(
114 array $aspect,
115 array $languages,
116 array $enhancers,
117 string $variableName = 'value',
118 string $templateSuffix = ''
119 ): array {
120 $dataSet = [];
121 foreach ($enhancers as $enhancer) {
122 foreach ($languages as $languageId => $expectation) {
123 $dataSet[] = [
124 array_merge(
125 $enhancer['enhancer'],
126 ['aspects' => [$variableName => $aspect]]
127 ),
128 $enhancer['parameters'],
129 $languageId,
130 $expectation,
131 ];
132 }
133 }
134 return $this->keysFromTemplate(
135 $dataSet,
136 'enhancer:%1$s, lang:%3$d' . $templateSuffix,
137 function (array $items) {
138 array_splice(
139 $items,
140 0,
141 1,
142 $items[0]['type']
143 );
144 return $items;
145 }
146 );
147 }
148
149 protected function getEnhancers(array $options = []): array
150 {
151 $options = array_merge(['name' => 'enhance', 'value' => 100], $options);
152 return [
153 [
154 'parameters' => sprintf('&value=%s', $options['value']),
155 'enhancer' => [
156 'type' => 'Simple',
157 'routePath' => sprintf('/%s/{value}', $options['name']),
158 '_arguments' => [],
159 ],
160 ],
161 [
162 'parameters' => sprintf('&testing[value]=%s', $options['value']),
163 'enhancer' => [
164 'type' => 'Plugin',
165 'routePath' => sprintf('/%s/{value}', $options['name']),
166 'namespace' => 'testing',
167 '_arguments' => [],
168 ],
169 ],
170 [
171 'parameters' => sprintf('&tx_testing_link[value]=%s&tx_testing_link[controller]=Link&tx_testing_link[action]=index', $options['value']),
172 'enhancer' => [
173 'type' => 'Extbase',
174 'routes' => [
175 [
176 'routePath' => sprintf('/%s/{value}', $options['name']),
177 '_controller' => 'Link::index',
178 '_arguments' => [],
179 ],
180 ],
181 'extension' => 'testing',
182 'plugin' => 'link',
183 ],
184 ],
185 ];
186 }
187
188 /**
189 * @return array
190 */
191 public function localeModifierDataProvider(): array
192 {
193 $aspect = [
194 'type' => 'LocaleModifier',
195 'default' => 'enhance',
196 'localeMap' => [
197 [
198 'locale' => 'fr_FR',
199 'value' => 'augmenter'
200 ]
201 ],
202 ];
203
204 $languages = [
205 '0' => 'https://acme.us/welcome/enhance/100?cHash=',
206 '1' => 'https://acme.fr/bienvenue/augmenter/100?cHash=',
207 ];
208
209 return $this->createDataSet(
210 $aspect,
211 $languages,
212 $this->getEnhancers(['name' => '{enhance_name}']),
213 'enhance_name'
214 );
215 }
216
217 /**
218 * @param array $enhancer
219 * @param string $additionalParameters
220 * @param int $targetLanguageId
221 * @param string $expectation
222 *
223 * @test
224 * @dataProvider localeModifierDataProvider
225 */
226 public function localeModifierIsApplied(array $enhancer, string $additionalParameters, int $targetLanguageId, string $expectation)
227 {
228 $this->mergeSiteConfiguration('acme-com', [
229 'routeEnhancers' => ['Enhancer' => $enhancer]
230 ]);
231
232 $response = $this->executeFrontendRequest(
233 (new InternalRequest('https://acme.us/'))
234 ->withPageId(1100)
235 ->withInstructions([
236 $this->createTypoLinkUrlInstruction([
237 'parameter' => 1100,
238 'language' => $targetLanguageId,
239 'additionalParams' => $additionalParameters,
240 'forceAbsoluteUrl' => 1,
241 ])
242 ]),
243 $this->internalRequestContext
244 );
245
246 static::assertStringStartsWith($expectation, (string)$response->getBody());
247 }
248
249 /**
250 * @return array
251 */
252 public function persistedAliasMapperDataProvider(): array
253 {
254 $aspect = [
255 'type' => 'PersistedAliasMapper',
256 'tableName' => 'pages',
257 'routeFieldName' => 'slug',
258 'routeValuePrefix' => '/',
259 ];
260
261 $languages = [
262 '0' => 'https://acme.us/welcome/enhance/welcome',
263 '1' => 'https://acme.fr/bienvenue/enhance/bienvenue',
264 ];
265
266 return $this->createDataSet(
267 $aspect,
268 $languages,
269 $this->getEnhancers(['value' => 1100])
270 );
271 }
272
273 /**
274 * @param array $enhancer
275 * @param string $additionalParameters
276 * @param int $targetLanguageId
277 * @param string $expectation
278 *
279 * @test
280 * @dataProvider persistedAliasMapperDataProvider
281 */
282 public function persistedAliasMapperIsApplied(array $enhancer, string $additionalParameters, int $targetLanguageId, string $expectation)
283 {
284 $this->mergeSiteConfiguration('acme-com', [
285 'routeEnhancers' => ['Enhancer' => $enhancer]
286 ]);
287
288 $response = $this->executeFrontendRequest(
289 (new InternalRequest('https://acme.us/'))
290 ->withPageId(1100)
291 ->withInstructions([
292 $this->createTypoLinkUrlInstruction([
293 'parameter' => 1100,
294 'language' => $targetLanguageId,
295 'additionalParams' => $additionalParameters,
296 'forceAbsoluteUrl' => 1,
297 ])
298 ]),
299 $this->internalRequestContext
300 );
301
302 static::assertSame($expectation, (string)$response->getBody());
303 }
304
305 /**
306 * @return array
307 */
308 public function persistedPatternMapperDataProvider(): array
309 {
310 $aspect = [
311 'type' => 'PersistedPatternMapper',
312 'tableName' => 'pages',
313 'routeFieldPattern' => '^(?P<subtitle>.+)-(?P<uid>\d+)$',
314 'routeFieldResult' => '{subtitle}-{uid}',
315 ];
316
317 $languages = [
318 '0' => 'https://acme.us/welcome/enhance/hello-and-welcome-1100',
319 '1' => 'https://acme.fr/bienvenue/enhance/salut-et-bienvenue-1100',
320 ];
321
322 return $this->createDataSet(
323 $aspect,
324 $languages,
325 $this->getEnhancers(['value' => 1100])
326 );
327 }
328
329 /**
330 * @param array $enhancer
331 * @param string $additionalParameters
332 * @param int $targetLanguageId
333 * @param string $expectation
334 *
335 * @test
336 * @dataProvider persistedPatternMapperDataProvider
337 */
338 public function persistedPatternMapperIsApplied(array $enhancer, string $additionalParameters, int $targetLanguageId, string $expectation)
339 {
340 $this->mergeSiteConfiguration('acme-com', [
341 'routeEnhancers' => ['Enhancer' => $enhancer]
342 ]);
343
344 $response = $this->executeFrontendRequest(
345 (new InternalRequest('https://acme.us/'))
346 ->withPageId(1100)
347 ->withInstructions([
348 $this->createTypoLinkUrlInstruction([
349 'parameter' => 1100,
350 'language' => $targetLanguageId,
351 'additionalParams' => $additionalParameters,
352 'forceAbsoluteUrl' => 1,
353 ])
354 ]),
355 $this->internalRequestContext
356 );
357
358 static::assertSame($expectation, (string)$response->getBody());
359 }
360
361 /**
362 * @return array
363 */
364 public function staticValueMapperDataProvider(): array
365 {
366 $aspect = [
367 'type' => 'StaticValueMapper',
368 'map' => [
369 'hundred' => 100,
370 ],
371 'localeMap' => [
372 [
373 'locale' => 'fr_FR',
374 'map' => [
375 'cent' => 100,
376 ],
377 ]
378 ],
379 ];
380
381 $languages = [
382 '0' => 'https://acme.us/welcome/enhance/hundred',
383 '1' => 'https://acme.fr/bienvenue/enhance/cent',
384 ];
385
386 return $this->createDataSet($aspect, $languages, $this->getEnhancers());
387 }
388
389 /**
390 * @param array $enhancer
391 * @param string $additionalParameters
392 * @param int $targetLanguageId
393 * @param string $expectation
394 *
395 * @test
396 * @dataProvider staticValueMapperDataProvider
397 */
398 public function staticValueMapperIsApplied(array $enhancer, string $additionalParameters, int $targetLanguageId, string $expectation)
399 {
400 $this->mergeSiteConfiguration('acme-com', [
401 'routeEnhancers' => ['Enhancer' => $enhancer]
402 ]);
403
404 $response = $this->executeFrontendRequest(
405 (new InternalRequest('https://acme.us/'))
406 ->withPageId(1100)
407 ->withInstructions([
408 $this->createTypoLinkUrlInstruction([
409 'parameter' => 1100,
410 'language' => $targetLanguageId,
411 'additionalParams' => $additionalParameters,
412 'forceAbsoluteUrl' => 1,
413 ])
414 ]),
415 $this->internalRequestContext
416 );
417
418 static::assertStringStartsWith($expectation, (string)$response->getBody());
419 }
420
421 /**
422 * @return array
423 */
424 public function staticRangeMapperDataProvider(): array
425 {
426 $aspect = [
427 'type' => 'StaticRangeMapper',
428 'start' => '1',
429 'end' => '100',
430 ];
431
432 $dataSet = [];
433 foreach (range(10, 100, 30) as $value) {
434 $languages = [
435 '0' => sprintf('https://acme.us/welcome/enhance/%s', $value),
436 '1' => sprintf('https://acme.fr/bienvenue/enhance/%s', $value),
437 ];
438
439 $dataSet = array_merge(
440 $dataSet,
441 $this->createDataSet(
442 $aspect,
443 $languages,
444 $this->getEnhancers(['value' => $value]),
445 'value',
446 sprintf(', value:%d', $value)
447 )
448 );
449 }
450 return $dataSet;
451 }
452
453 /**
454 * @param array $enhancer
455 * @param string $additionalParameters
456 * @param int $targetLanguageId
457 * @param string $expectation
458 *
459 * @test
460 * @dataProvider staticRangeMapperDataProvider
461 */
462 public function staticRangeMapperIsApplied(array $enhancer, string $additionalParameters, int $targetLanguageId, string $expectation)
463 {
464 $this->mergeSiteConfiguration('acme-com', [
465 'routeEnhancers' => ['Enhancer' => $enhancer]
466 ]);
467
468 $response = $this->executeFrontendRequest(
469 (new InternalRequest('https://acme.us/'))
470 ->withPageId(1100)
471 ->withInstructions([
472 $this->createTypoLinkUrlInstruction([
473 'parameter' => 1100,
474 'language' => $targetLanguageId,
475 'additionalParams' => $additionalParameters,
476 'forceAbsoluteUrl' => 1,
477 ])
478 ]),
479 $this->internalRequestContext
480 );
481
482 static::assertStringStartsWith($expectation, (string)$response->getBody());
483 }
484 }