‪TYPO3CMS  11.5
SiteResolverTest.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 Prophecy\PhpUnit\ProphecyTrait;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
23 use Psr\Http\Server\RequestHandlerInterface;
35 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
36 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
37 
38 class ‪SiteResolverTest extends UnitTestCase
39 {
40  use ProphecyTrait;
41 
45  protected ‪$resetSingletonInstances = true;
46 
50  protected AccessibleObjectInterface ‪$siteFinder;
51 
52  protected RequestHandlerInterface ‪$siteFoundRequestHandler;
53  protected string ‪$originalLocale;
54 
58  protected function ‪setUp(): void
59  {
60  parent::setUp();
61  $this->originalLocale = setlocale(LC_COLLATE, '0');
62  $this->siteFinder = $this->getAccessibleMock(SiteFinder::class, ['dummy'], [], '', false);
63 
64  // A request handler which expects a site to be found.
65  $this->siteFoundRequestHandler = new class () implements RequestHandlerInterface {
66  public function handle(ServerRequestInterface $request): ResponseInterface
67  {
70  $site = $request->getAttribute('site', false);
71  $language = $request->getAttribute('language', false);
72  if ($site && $language) {
73  return new ‪JsonResponse(
74  [
75  'site' => $site->getIdentifier(),
76  'language-id' => $language->getLanguageId(),
77  'language-base' => (string)$language->getBase(),
78  'rootpage' => $site->getRootPageId(),
79  ]
80  );
81  }
82  return new ‪NullResponse();
83  }
84  };
85 
86  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
87  GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
88  }
89 
90  protected function ‪tearDown(): void
91  {
92  // restore locale to original setting
93  setlocale(LC_COLLATE, $this->originalLocale);
94  setlocale(LC_MONETARY, $this->originalLocale);
95  setlocale(LC_TIME, $this->originalLocale);
96  parent::tearDown();
97  }
98 
107  public function ‪detectASingleSiteWhenProperRequestIsGiven(): void
108  {
109  $incomingUrl = 'https://a-random-domain.com/mysite/';
110  $siteIdentifier = 'full-site';
111  $this->siteFinder->_set('sites', [
112  $siteIdentifier => new Site($siteIdentifier, 13, [
113  'base' => '/mysite/',
114  'languages' => [
115  0 => [
116  'languageId' => 0,
117  'locale' => 'fr_FR.UTF-8',
118  'base' => '/',
119  ],
120  ],
121  ]),
122  ]);
123 
124  $featuresMock = $this->‪createFeaturesMock();
125  GeneralUtility::addInstance(Features::class, $featuresMock);
126  $subject = new SiteResolver(new SiteMatcher($this->siteFinder));
127 
128  $request = new ServerRequest($incomingUrl, 'GET');
129  $response = $subject->process($request, $this->siteFoundRequestHandler);
130 
131  if ($response instanceof NullResponse) {
132  self::fail('No site configuration found in URL ' . $incomingUrl . '.');
133  } else {
134  $result = $response->getBody()->getContents();
135  $result = json_decode($result, true);
136  self::assertEquals($siteIdentifier, $result['site']);
137  self::assertEquals(0, $result['language-id']);
138  self::assertEquals('/mysite/', $result['language-base']);
139  }
140  }
141 
153  public function ‪detectSubsiteInsideNestedUrlStructure(): void
154  {
155  $incomingUrl = 'https://www.random-result.com/mysubsite/you-know-why/';
156  $this->siteFinder->_set('sites', [
157  'outside-site' => new Site('outside-site', 13, [
158  'base' => '/',
159  'languages' => [
160  0 => [
161  'languageId' => 0,
162  'locale' => 'fr_FR.UTF-8',
163  'base' => '/',
164  ],
165  ],
166  ]),
167  'sub-site' => new Site('sub-site', 15, [
168  'base' => '/mysubsite/',
169  'languages' => [
170  0 => [
171  'languageId' => 0,
172  'locale' => 'fr_FR.UTF-8',
173  'base' => '/',
174  ],
175  ],
176  ]),
177  ]);
178 
179  $featuresMock = $this->‪createFeaturesMock();
180  GeneralUtility::addInstance(Features::class, $featuresMock);
181  $subject = new SiteResolver(new SiteMatcher($this->siteFinder));
182 
183  $request = new ServerRequest($incomingUrl, 'GET');
184  $response = $subject->process($request, $this->siteFoundRequestHandler);
185  if ($response instanceof NullResponse) {
186  self::fail('No site configuration found in URL ' . $incomingUrl . '.');
187  } else {
188  $result = $response->getBody()->getContents();
189  $result = json_decode($result, true);
190  self::assertEquals('sub-site', $result['site']);
191  self::assertEquals(0, $result['language-id']);
192  self::assertEquals('/mysubsite/', $result['language-base']);
193  }
194  }
195 
197  {
198  return [
199  'matches second site' => [
200  'https://www.random-result.com/mysubsite/you-know-why/',
201  'sub-site',
202  14,
203  '/mysubsite/',
204  ],
205  'matches third site' => [
206  'https://www.random-result.com/mysubsite/micro-site/oh-yes-you-do/',
207  'subsub-site',
208  15,
209  '/mysubsite/micro-site/',
210  ],
211  'matches a subsite in first site' => [
212  'https://www.random-result.com/products/pampers/',
213  'outside-site',
214  13,
215  '/',
216  ],
217  ];
218  }
219 
236  public function ‪detectSubSubsiteInsideNestedUrlStructure($incomingUrl, $expectedSiteIdentifier, $expectedRootPageId, $expectedBase): void
237  {
238  $this->siteFinder->_set('sites', [
239  'outside-site' => new Site('outside-site', 13, [
240  'base' => '/',
241  'languages' => [
242  0 => [
243  'languageId' => 0,
244  'locale' => 'fr_FR.UTF-8',
245  'base' => '/',
246  ],
247  ],
248  ]),
249  'sub-site' => new Site('sub-site', 14, [
250  'base' => '/mysubsite/',
251  'languages' => [
252  0 => [
253  'languageId' => 0,
254  'locale' => 'fr_FR.UTF-8',
255  'base' => '/',
256  ],
257  ],
258  ]),
259  'subsub-site' => new Site('subsub-site', 15, [
260  'base' => '/mysubsite/micro-site/',
261  'languages' => [
262  0 => [
263  'languageId' => 0,
264  'locale' => 'fr_FR.UTF-8',
265  'base' => '/',
266  ],
267  ],
268  ]),
269  ]);
270 
271  $featuresMock = $this->‪createFeaturesMock();
272  GeneralUtility::addInstance(Features::class, $featuresMock);
273  $subject = new SiteResolver(new SiteMatcher($this->siteFinder));
274 
275  $request = new ServerRequest($incomingUrl, 'GET');
276  $response = $subject->process($request, $this->siteFoundRequestHandler);
277 
278  if ($response instanceof NullResponse) {
279  self::fail('No site configuration found in URL ' . $incomingUrl . '.');
280  } else {
281  $result = $response->getBody()->getContents();
282  $result = json_decode($result, true);
283  self::assertEquals($expectedSiteIdentifier, $result['site']);
284  self::assertEquals($expectedRootPageId, $result['rootpage']);
285  self::assertEquals($expectedBase, $result['language-base']);
286  }
287  }
288 
289  public function ‪detectProperLanguageByIncomingUrlDataProvider(): array
290  {
291  return [
292  'matches second site' => [
293  'https://www.random-result.com/mysubsite/you-know-why/',
294  'sub-site',
295  14,
296  2,
297  '/mysubsite/',
298  ],
299  'matches second site in other language' => [
300  'https://www.random-result.com/mysubsite/it/you-know-why/',
301  'sub-site',
302  14,
303  2,
304  '/mysubsite/',
305  ],
306  'matches third site' => [
307  'https://www.random-result.com/mysubsite/micro-site/ru/oh-yes-you-do/',
308  'subsub-site',
309  15,
310  13,
311  '/mysubsite/micro-site/ru/',
312  ],
313  'matches a subpage in first site' => [
314  'https://www.random-result.com/en/products/pampers/',
315  'outside-site',
316  13,
317  0,
318  '/en/',
319  ],
320  'matches a subpage with translation in first site' => [
321  'https://www.random-result.com/fr/products/pampers/',
322  'outside-site',
323  13,
324  1,
325  '/fr/',
326  ],
327  ];
328  }
329 
343  public function ‪detectProperLanguageByIncomingUrl($incomingUrl, $expectedSiteIdentifier, $expectedRootPageId, $expectedLanguageId, $expectedBase): void
344  {
345  $this->siteFinder->_set('sites', [
346  'outside-site' => new Site('outside-site', 13, [
347  'base' => '/',
348  'languages' => [
349  0 => [
350  'languageId' => 0,
351  'locale' => 'en_US.UTF-8',
352  'base' => '/en/',
353  ],
354  1 => [
355  'languageId' => 1,
356  'locale' => 'fr_CA.UTF-8',
357  'base' => '/fr/',
358  ],
359  ],
360  ]),
361  'sub-site' => new Site('sub-site', 14, [
362  'base' => '/mysubsite/',
363  'languages' => [
364  2 => [
365  'languageId' => 2,
366  'locale' => 'it_IT.UTF-8',
367  'base' => '/',
368  ],
369  ],
370  ]),
371  'subsub-site' => new Site('subsub-site', 15, [
372  'base' => '/mysubsite/micro-site/',
373  'languages' => [
374  13 => [
375  'languageId' => 13,
376  'locale' => 'ru_RU.UTF-8',
377  'base' => '/ru/',
378  ],
379  ],
380  ]),
381  ]);
382 
383  $featuresMock = $this->‪createFeaturesMock();
384  GeneralUtility::addInstance(Features::class, $featuresMock);
385  $subject = new SiteResolver(new SiteMatcher($this->siteFinder));
386 
387  $request = new ServerRequest($incomingUrl, 'GET');
388  $response = $subject->process($request, $this->siteFoundRequestHandler);
389 
390  if ($response instanceof NullResponse) {
391  self::fail('No site configuration found in URL ' . $incomingUrl . '.');
392  } else {
393  $result = $response->getBody()->getContents();
394  $result = json_decode($result, true);
395  self::assertEquals($expectedSiteIdentifier, $result['site']);
396  self::assertEquals($expectedRootPageId, $result['rootpage']);
397  self::assertEquals($expectedLanguageId, $result['language-id']);
398  self::assertEquals($expectedBase, $result['language-base']);
399  }
400  }
401 
402  private function ‪createFeaturesMock(): ‪Features
403  {
404  $mock = $this->getMockBuilder(Features::class)
405  ->onlyMethods(['isFeatureEnabled'])
406  ->getMock();
407  $mock->expects(self::any())
408  ->method('isFeatureEnabled')
409  ->with('security.frontend.allowInsecureSiteResolutionByQueryParameters')
410  ->willReturn(false);
411  return $mock;
412  }
413 }
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectProperLanguageByIncomingUrlDataProvider
‪detectProperLanguageByIncomingUrlDataProvider()
Definition: SiteResolverTest.php:287
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\$siteFoundRequestHandler
‪RequestHandlerInterface $siteFoundRequestHandler
Definition: SiteResolverTest.php:50
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\$resetSingletonInstances
‪bool $resetSingletonInstances
Definition: SiteResolverTest.php:43
‪TYPO3\CMS\Core\Http\NullResponse
Definition: NullResponse.php:26
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest
Definition: SiteResolverTest.php:39
‪TYPO3\CMS\Frontend\Middleware\SiteResolver
Definition: SiteResolver.php:37
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectASingleSiteWhenProperRequestIsGiven
‪detectASingleSiteWhenProperRequestIsGiven()
Definition: SiteResolverTest.php:105
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware
Definition: PageArgumentValidatorTest.php:18
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\tearDown
‪tearDown()
Definition: SiteResolverTest.php:88
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:56
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:37
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectProperLanguageByIncomingUrl
‪detectProperLanguageByIncomingUrl($incomingUrl, $expectedSiteIdentifier, $expectedRootPageId, $expectedLanguageId, $expectedBase)
Definition: SiteResolverTest.php:341
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\createFeaturesMock
‪createFeaturesMock()
Definition: SiteResolverTest.php:400
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\$originalLocale
‪string $originalLocale
Definition: SiteResolverTest.php:51
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectSubSubsiteInsideNestedUrlStructure
‪detectSubSubsiteInsideNestedUrlStructure($incomingUrl, $expectedSiteIdentifier, $expectedRootPageId, $expectedBase)
Definition: SiteResolverTest.php:234
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\setUp
‪setUp()
Definition: SiteResolverTest.php:56
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectSubSubsiteInsideNestedUrlStructureDataProvider
‪detectSubSubsiteInsideNestedUrlStructureDataProvider()
Definition: SiteResolverTest.php:194
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Routing\SiteMatcher
Definition: SiteMatcher.php:52
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\detectSubsiteInsideNestedUrlStructure
‪detectSubsiteInsideNestedUrlStructure()
Definition: SiteResolverTest.php:151
‪TYPO3\CMS\Frontend\Tests\Unit\Middleware\SiteResolverTest\$siteFinder
‪AccessibleObjectInterface $siteFinder
Definition: SiteResolverTest.php:48