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