‪TYPO3CMS  ‪main
PersistedAliasMapperTest.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 Psr\EventDispatcher\EventDispatcherInterface;
30 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
31 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
32 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
33 
34 final class ‪PersistedAliasMapperTest extends FunctionalTestCase
35 {
36  private const ‪ASPECT_CONFIGURATION = [
37  'tableName' => 'tt_content',
38  'routeFieldName' => 'header',
39  ];
40 
41  private const ‪SLUG_CONFIGURATION = [
42  'type' => 'slug',
43  'generatorOptions' => [
44  'prefixParentPageSlug' => false,
45  ],
46  'fallbackCharacter' => '-',
47  'required' => true,
48  'eval' => 'uniqueInSite',
49  'default' => '',
50  ];
51 
52  private const ‪LANGUAGE_MAP = [
53  'es-es' => 3,
54  'fr-ca' => 2,
55  'fr-fr' => 1,
56  'default' => 0,
57  ];
58 
59  private const ‪SITE_ADDITION = [
60  'acme' => 0,
61  'other' => 4000,
62  ];
63 
65 
67  private array ‪$sites;
68 
69  protected function ‪setUp(): void
70  {
71  parent::setUp();
72 
73  $this->withDatabaseSnapshot(function () {
74  $this->importCSVDataSet(__DIR__ . '/../../Fixtures/be_users.csv');
75  $backendUser = $this->setUpBackendUser(1);
77  $scenarioFile = __DIR__ . '/Fixtures/AspectScenario.yaml';
78  $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
79  $writer = DataHandlerWriter::withBackendUser($backendUser);
80  $writer->invokeFactory($factory);
81  if (!empty($writer->getErrors())) {
82  self::fail(var_export($writer->getErrors(), true));
83  }
84  });
85 
86  // declare tt_content.header as `slug` field having `uniqueInSite` set
87  $tableName = self::ASPECT_CONFIGURATION['tableName'];
88  $fieldName = self::ASPECT_CONFIGURATION['routeFieldName'];
89  ‪$GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'] = ‪self::SLUG_CONFIGURATION;
90 
91  ‪$languages = [
92  [
93  'languageId' => 3,
94  'base' => '/es-es/',
95  'locale' => 'es_ES.UTF-8',
96  'fallbackType' => 'fallback',
97  'fallbacks' => [0],
98  'title' => 'Spanish',
99  ],
100  [
101  'languageId' => 2,
102  'base' => '/fr-ca/',
103  'locale' => 'fr_CA.UTF-8',
104  'fallbackType' => 'fallback',
105  'fallbacks' => [1, 0],
106  'title' => 'Franco-Canadian',
107  ],
108  [
109  'languageId' => 1,
110  'base' => '/fr-fr/',
111  'locale' => 'fr_FR.UTF-8',
112  'fallbackType' => 'fallback',
113  'fallbacks' => [0],
114  'French',
115  ],
116  [
117  'languageId' => 0,
118  'base' => 'en_US.UTF-8',
119  'locale' => '/en-us/',
120  ],
121  ];
122  $this->sites = [
123  'acme' => new ‪Site('acme-inc', 1000, [
124  'identifier' => 'acme-inc',
125  'rootPageId' => 1000,
126  'base' => 'https://acme.com/',
127  'languages' => ‪$languages,
128  ]),
129  'other' => new ‪Site('other-inc', 5000, [
130  'identifier' => 'other-inc',
131  'rootPageId' => 5000,
132  'base' => 'https://other.com/',
133  'languages' => ‪$languages,
134  ]),
135  ];
136  $this->‪writeSiteConfiguration($this->sites['acme']);
137  $this->‪writeSiteConfiguration($this->sites['other']);
138  $this->subject = new ‪PersistedAliasMapper(self::ASPECT_CONFIGURATION);
139  $this->subject->setSiteLanguage($this->sites['acme']->getLanguageById(0));
140  $this->subject->setSite($this->sites['acme']);
141  }
142 
143  protected function ‪tearDown(): void
144  {
145  unset($this->subject, $this->sites);
146  parent::tearDown();
147  }
148 
149  public static function ‪languageAwareRecordsAreResolvedDataProvider(): array
150  {
151  $baseDataSet = [
152  'non-existing, default language' => ['this-value-does-not-exist', 'default', null],
153 
154  '30xx-slug, default language' => ['30xx-slug', 'default', '3010'],
155  '30xx-slug, fr-fr language' => ['30xx-slug', 'fr-fr', '3010'],
156  '30xx-slug, fr-ca language' => ['30xx-slug', 'fr-ca', '3010'],
157 
158  '30xx-slug-fr-ca, fr-ca language' => ['30xx-slug-fr-ca', 'fr-ca', '3010'],
159  // '30xx-slug-fr-ca' available in default language as well, fallbacks to that one
160  '30xx-slug-fr-ca, fr-fr language' => ['30xx-slug-fr-ca', 'fr-fr', '3030'],
161  // '30xx-slug-fr-ca' available in default language, use it directly
162  '30xx-slug-fr-ca, default language' => ['30xx-slug-fr-ca', 'default', '3030'],
163 
164  '30xx-slug-fr, fr-ca language' => ['30xx-slug-fr', 'fr-ca', '3010'],
165  '30xx-slug-fr, fr-fr language' => ['30xx-slug-fr', 'fr-fr', '3010'],
166  // '30xx-slug-fr-ca' available in default language, use it directly
167  '30xx-slug-fr, default language' => ['30xx-slug-fr', 'default', '3020'],
168 
169  // basically the same, but being stored in reverse order in database
170  '40xx-slug, default language' => ['40xx-slug', 'default', '4040'],
171  '40xx-slug, fr-fr language' => ['40xx-slug', 'fr-fr', '4040'],
172  '40xx-slug, fr-ca language' => ['40xx-slug', 'fr-ca', '4040'],
173 
174  '40xx-slug-fr-ca, fr-ca language' => ['40xx-slug-fr-ca', 'fr-ca', '4040'],
175  // '40xx-slug-fr-ca' available in default language as well, fallbacks to that one
176  '40xx-slug-fr-ca, fr-fr language' => ['40xx-slug-fr-ca', 'fr-fr', '4030'],
177  // '40xx-slug-fr-ca' available in default language, use it directly
178  '40xx-slug-fr-ca, default language' => ['40xx-slug-fr-ca', 'default', '4030'],
179 
180  '40xx-slug-fr, fr-ca language' => ['40xx-slug-fr', 'fr-ca', '4040'],
181  '40xx-slug-fr, fr-fr language' => ['40xx-slug-fr', 'fr-fr', '4040'],
182  // '40xx-slug-fr-ca' available in default language, use it directly
183  '40xx-slug-fr, default language' => ['40xx-slug-fr', 'default', '4020'],
184  ];
185  // permute $baseDataSet to be either prepended
186  // with site identifier argument 'acme' or 'other'
187  $dataSet = [];
188  foreach (['acme', 'other'] as $site) {
189  foreach ($baseDataSet as $key => $arguments) {
190  array_unshift($arguments, $site);
191  $dataSet[$site . ':' . $key] = $arguments;
192  }
193  }
194  return $dataSet;
195  }
196 
201  public function ‪languageAwareRecordsAreResolved(string ‪$identifier, string $requestValue, string $language, ?string $expectation): void
202  {
203  $this->subject->setSiteLanguage(
204  $this->sites[‪$identifier]->getLanguageById(self::LANGUAGE_MAP[$language])
205  );
206  $this->subject->setSite(
207  $this->sites[‪$identifier]
208  );
209  if ($expectation !== null) {
210  $expectation = (string)((int)$expectation + self::SITE_ADDITION[‪$identifier]);
211  }
212  self::assertSame($expectation, $this->subject->resolve($requestValue));
213  }
214 
215  public static function ‪recordVisibilityDataProvider(): array
216  {
217  $rawContext = new ‪Context();
218  $visibleContext = new ‪Context();
219  $visibleContext->setAspect(
220  'visibility',
221  new ‪VisibilityAspect(false, true, false)
222  );
223  $frontendGroupsContext = new ‪Context();
224  $frontendGroupsContext->setAspect(
225  'frontend.user',
226  new ‪UserAspect(null, [13])
227  );
228  $scheduledContext = new ‪Context();
229  $scheduledContext->setAspect(
230  'date',
231  new ‪DateTimeAspect(new \DateTimeImmutable('@20000'))
232  );
233 
234  return [
235  'hidden-visibility-slug, raw context' => [
236  $rawContext,
237  ['slug' => 'hidden-visibility-slug', 'uid' => '4051'],
238  false,
239  ],
240  // fe_group slugs are always considered
241  'restricted-visibility-slug, raw context' => [
242  $rawContext,
243  ['slug' => 'restricted-visibility-slug', 'uid' => '4052'],
244  true,
245  ],
246  'scheduled-visibility-slug, raw context' => [
247  $rawContext,
248  ['slug' => 'scheduled-visibility-slug', 'uid' => '4053'],
249  false,
250  ],
251  'hidden-visibility-slug, visibility context (include hidden content)' => [
252  $visibleContext,
253  ['slug' => 'hidden-visibility-slug', 'uid' => '4051'],
254  true,
255  ],
256  // fe_group slugs are always considered
257  'restricted-visibility-slug, frontend-groups context (13)' => [
258  $frontendGroupsContext,
259  ['slug' => 'restricted-visibility-slug', 'uid' => '4052'],
260  true,
261  ],
262  'scheduled-visibility-slug, scheduled context (timestamp 20000)' => [
263  $scheduledContext,
264  ['slug' => 'scheduled-visibility-slug', 'uid' => '4053'],
265  false, // @todo actually `true`, Start-/EndTimeRestriction do not support Context, yet
266  ],
267  ];
268  }
269 
274  public function ‪recordVisibilityIsConsideredForResolving(‪Context $context, array $parameters, bool $expectation): void
275  {
276  $this->subject->setContext($context);
277  $expectedResult = $expectation ? $parameters['uid'] : null;
278  self::assertSame($expectedResult, $this->subject->resolve($parameters['slug']));
279  }
280 
285  public function ‪recordVisibilityIsConsideredForGeneration(‪Context $context, array $parameters, bool $expectation): void
286  {
287  $this->subject->setContext($context);
288  $expectedResult = $expectation ? $parameters['slug'] : null;
289  self::assertSame($expectedResult, $this->subject->generate($parameters['uid']));
290  }
291 
296  {
297  $result = $this->subject->generate('3010');
298 
299  self::assertSame('30xx-slug', $result);
300  }
301 
306  {
307  $result = $this->subject->generate('3010-i-am-garbage');
308 
309  self::assertNull($result);
310  }
311 
312  private function ‪writeSiteConfiguration(‪Site $site): void
313  {
314  try {
315  // ensure no previous site configuration influences the test
316  $path = $this->instancePath . '/typo3conf/sites';
317  $cache = $this->get('cache.core');
318  $eventDispatcher = $this->get(EventDispatcherInterface::class);
319  ‪GeneralUtility::rmdir($path . '/' . $site->‪getIdentifier(), true);
320  GeneralUtility::makeInstance(SiteConfiguration::class, $path, $eventDispatcher, $cache)->write($site->‪getIdentifier(), $site->‪getConfiguration());
321  } catch (\‪Exception $exception) {
322  self::markTestSkipped($exception->getMessage());
323  }
324  }
325 }
‪TYPO3\CMS\Core\Context\VisibilityAspect
Definition: VisibilityAspect.php:31
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\recordVisibilityIsConsideredForGeneration
‪recordVisibilityIsConsideredForGeneration(Context $context, array $parameters, bool $expectation)
Definition: PersistedAliasMapperTest.php:285
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\LANGUAGE_MAP
‪const LANGUAGE_MAP
Definition: PersistedAliasMapperTest.php:52
‪TYPO3\CMS\Core\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\tearDown
‪tearDown()
Definition: PersistedAliasMapperTest.php:143
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\generateWithUidOfExistingPageReturnsPageSlug
‪generateWithUidOfExistingPageReturnsPageSlug()
Definition: PersistedAliasMapperTest.php:295
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\SLUG_CONFIGURATION
‪const SLUG_CONFIGURATION
Definition: PersistedAliasMapperTest.php:41
‪$languages
‪$languages
Definition: updateIsoDatabase.php:104
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\generateWithUidOfExistingPageSuffixedWithGarbageStringReturnsNull
‪generateWithUidOfExistingPageSuffixedWithGarbageStringReturnsNull()
Definition: PersistedAliasMapperTest.php:305
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect
Definition: PersistedAliasMapperTest.php:18
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Core\Configuration\SiteConfiguration
Definition: SiteConfiguration.php:47
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\languageAwareRecordsAreResolved
‪languageAwareRecordsAreResolved(string $identifier, string $requestValue, string $language, ?string $expectation)
Definition: PersistedAliasMapperTest.php:201
‪TYPO3\CMS\Core\Core\Bootstrap\initializeLanguageObject
‪static initializeLanguageObject()
Definition: Bootstrap.php:539
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\SITE_ADDITION
‪const SITE_ADDITION
Definition: PersistedAliasMapperTest.php:59
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\writeSiteConfiguration
‪writeSiteConfiguration(Site $site)
Definition: PersistedAliasMapperTest.php:312
‪TYPO3\CMS\Core\Utility\GeneralUtility\rmdir
‪static bool rmdir(string $path, bool $removeNonEmpty=false)
Definition: GeneralUtility.php:1679
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper
Definition: PersistedAliasMapper.php:55
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\$subject
‪PersistedAliasMapper $subject
Definition: PersistedAliasMapperTest.php:64
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest
Definition: PersistedAliasMapperTest.php:35
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\$sites
‪array $sites
Definition: PersistedAliasMapperTest.php:67
‪TYPO3\CMS\Core\Site\Entity\Site\getConfiguration
‪getConfiguration()
Definition: Site.php:294
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Bootstrap
Definition: Bootstrap.php:64
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\languageAwareRecordsAreResolvedDataProvider
‪static languageAwareRecordsAreResolvedDataProvider()
Definition: PersistedAliasMapperTest.php:149
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\recordVisibilityIsConsideredForResolving
‪recordVisibilityIsConsideredForResolving(Context $context, array $parameters, bool $expectation)
Definition: PersistedAliasMapperTest.php:274
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\recordVisibilityDataProvider
‪static recordVisibilityDataProvider()
Definition: PersistedAliasMapperTest.php:215
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\ASPECT_CONFIGURATION
‪const ASPECT_CONFIGURATION
Definition: PersistedAliasMapperTest.php:36
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Core\Context\DateTimeAspect
Definition: DateTimeAspect.php:35
‪TYPO3\CMS\Core\Site\Entity\Site\getIdentifier
‪getIdentifier()
Definition: Site.php:173
‪TYPO3\CMS\Core\Context\UserAspect
Definition: UserAspect.php:37
‪TYPO3\CMS\Core\Tests\Functional\Routing\Aspect\PersistedAliasMapperTest\setUp
‪setUp()
Definition: PersistedAliasMapperTest.php:69
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37