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