‪TYPO3CMS  11.5
SiteMatcherTest.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 
27 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
28 
29 class ‪SiteMatcherTest extends UnitTestCase
30 {
35  {
36  $site = new ‪Site('main', 1, [
37  'base' => '/',
38  'languages' => [
39  0 => [
40  'title' => 'English',
41  'languageId' => 0,
42  'base' => 'http://9-5.typo3.test/',
43  'locale' => 'en_US-UTF-8',
44  ],
45  2 => [
46  'title' => 'Deutsch',
47  'languageId' => 2,
48  'base' => 'http://de.9-5.typo3.test/',
49  'locale' => 'en_US-UTF-8',
50  ],
51  1 => [
52  'title' => 'Dansk',
53  'languageId' => 1,
54  'base' => 'http://9-5.typo3.test/da/',
55  'locale' => 'da_DK.UTF-8',
56  ],
57  ],
58  ]);
59  $secondSite = new ‪Site('second', 13, [
60  'base' => '/',
61  'languages' => [
62  0 => [
63  'title' => 'English',
64  'languageId' => 0,
65  'base' => '/en/',
66  'locale' => 'en_US-UTF-8',
67  ],
68  1 => [
69  'title' => 'Dansk',
70  'languageId' => 1,
71  'base' => '/da/',
72  'locale' => 'da_DK.UTF-8',
73  ],
74  ],
75  ]);
76  $featuresMock = $this->‪createFeaturesMock();
77  GeneralUtility::addInstance(Features::class, $featuresMock);
78  $finderMock = $this->‪createSiteFinderMock($site, $secondSite);
79  $subject = new ‪SiteMatcher($finderMock);
80 
81  $request = new ‪ServerRequest('http://9-5.typo3.test/da/my-page/');
83  $result = $subject->matchRequest($request);
84  self::assertEquals(1, $result->getLanguage()->getLanguageId());
85 
86  $request = new ‪ServerRequest('http://9-5.typo3.test/da');
88  $result = $subject->matchRequest($request);
89  // Matches danish, as path fits
90  self::assertEquals(1, $result->getLanguage()->getLanguageId());
91 
92  $request = new ‪ServerRequest('https://9-5.typo3.test/da');
94  $result = $subject->matchRequest($request);
95  // Matches the second site, as this is HTTPS and HTTP
96  self::assertEquals('second', $result->getSite()->getIdentifier());
97  self::assertEquals(1, $result->getLanguage()->getLanguageId());
98 
99  $request = new ‪ServerRequest('http://de.9-5.typo3.test/da');
101  $result = $subject->matchRequest($request);
102  // Matches german, as the domain fits!
103  self::assertEquals(2, $result->getLanguage()->getLanguageId());
104 
105  $request = new ‪ServerRequest('http://9-5.typo3.test/');
107  $result = $subject->matchRequest($request);
108  // Matches english
109  self::assertEquals(0, $result->getLanguage()->getLanguageId());
110 
111  // @todo this is a random result and needs to be refined
112  // www.example.com is not defined at all, but it actually "matches"...
113  $request = new ‪ServerRequest('http://www.example.com/');
115  $result = $subject->matchRequest($request);
116  // finds the second site, since that configuration does not have a host part, thus only `/` matches
117  // @todo for future versions (TYPO3 v12+) this should be adjusted and be more explicit by enforcing host names
118  self::assertNull($result->getLanguage());
119  self::assertEquals('second', $result->getSite()->getIdentifier());
120  }
121 
127  {
128  $site = new ‪Site('main', 1, [
129  'base' => 'https://www.example.com/',
130  'languages' => [
131  0 => [
132  'title' => 'English',
133  'languageId' => 0,
134  'base' => 'http://example.us/',
135  'locale' => 'en_US-UTF-8',
136  ],
137  2 => [
138  'title' => 'Deutsch',
139  'languageId' => 2,
140  'base' => 'http://www.example.de/',
141  'locale' => 'en_US-UTF-8',
142  ],
143  1 => [
144  'title' => 'Dansk',
145  'languageId' => 1,
146  'base' => 'http://www.example.com/da/',
147  'locale' => 'da_DK.UTF-8',
148  ],
149  3 => [
150  'title' => 'French',
151  'languageId' => 3,
152  'base' => '/fr/',
153  'locale' => 'fr_FR.UTF-8',
154  ],
155  ],
156  ]);
157  $secondSite = new ‪Site('second', 13, [
158  'base' => '/',
159  'languages' => [
160  0 => [
161  'title' => 'English',
162  'languageId' => 0,
163  'base' => '/en/',
164  'locale' => 'en_US-UTF-8',
165  ],
166  1 => [
167  'title' => 'Dansk',
168  'languageId' => 1,
169  'base' => '/da/',
170  'locale' => 'da_DK.UTF-8',
171  ],
172  ],
173  ]);
174  $featuresMock = $this->‪createFeaturesMock();
175  GeneralUtility::addInstance(Features::class, $featuresMock);
176  $finderMock = $this->‪createSiteFinderMock($site, $secondSite);
177  $subject = new ‪SiteMatcher($finderMock);
178 
179  $request = new ‪ServerRequest('https://www.example.com/de');
181  $result = $subject->matchRequest($request);
182  // Site found, but no language
183  self::assertEquals($site, $result->getSite());
184  self::assertNull($result->getLanguage());
185 
186  $request = new ‪ServerRequest('http://www.other-domain.com/da');
188  $result = $subject->matchRequest($request);
189  self::assertEquals($secondSite, $result->getSite());
190  self::assertEquals(1, $result->getLanguage()->getLanguageId());
191 
192  $request = new ‪ServerRequest('http://www.other-domain.com/de');
194  $result = $subject->matchRequest($request);
195  // No language for this solution
196  self::assertEquals($secondSite, $result->getSite());
197  self::assertNull($result->getLanguage());
198  }
199 
200  public static function ‪bestMatchingUrlIsUsedDataProvider(): \Generator
201  {
202  yield ['https://example.org/page', '1-main', 'en_US'];
203  yield ['https://example.org/', '1-main', 'en_US'];
204  yield ['https://example.org/f', '1-main', 'en_US'];
205  yield ['https://example.org/fr', '3-fr', 'fr_FR'];
206  yield ['https://example.org/friendly-page', '1-main', 'en_US'];
207  yield ['https://example.org/fr/', '3-fr', 'fr_FR'];
208  yield ['https://example.org/fr/page', '3-fr', 'fr_FR'];
209  yield ['https://example.org/de', '1-main', 'de_DE'];
210  yield ['https://example.org/deterministic', '1-main', 'en_US'];
211  yield ['https://example.org/dk', '2-dk', 'da_DK'];
212  yield ['https://example.org/dkother', '1-main', 'en_US'];
213  }
214 
219  public function ‪bestMatchingUrlIsUsed(string $requestUri, string $expectedSite, string $expectedLocale): void
220  {
221  $mainSite = new ‪Site('1-main', 31, [
222  'base' => 'https://example.org/',
223  'languages' => [
224  [
225  'languageId' => 0,
226  'base' => 'https://example.org/',
227  'locale' => 'en_US',
228  ],
229  [
230  'languageId' => 2,
231  'base' => 'https://example.org/de/',
232  'locale' => 'de_DE',
233  ],
234  ],
235  ]);
236  $dkSite = new ‪Site('2-dk', 21, [
237  'base' => 'https://example.org/',
238  'languages' => [
239  [
240  'languageId' => 0,
241  'base' => 'https://example.org/dk/',
242  'locale' => 'da_DK',
243  ],
244  ],
245  ]);
246  $frSite = new ‪Site('3-fr', 11, [
247  'base' => 'https://example.org/',
248  'languages' => [
249  [
250  'languageId' => 0,
251  'base' => 'https://example.org/fr/',
252  'locale' => 'fr_FR',
253  ],
254  ],
255  ]);
256 
257  $featuresMock = $this->‪createFeaturesMock();
258  GeneralUtility::addInstance(Features::class, $featuresMock);
259  $finderMock = $this->‪createSiteFinderMock($mainSite, $dkSite, $frSite);
260  $subject = new ‪SiteMatcher($finderMock);
261 
262  $request = new ‪ServerRequest($requestUri);
264  $result = $subject->matchRequest($request);
265 
266  self::assertSame($expectedSite, $result->getSite()->getIdentifier());
267  self::assertSame($expectedLocale, $result->getLanguage()->getLocale());
268  }
269 
270  private function ‪createFeaturesMock(): ‪Features
271  {
272  $mock = $this->getMockBuilder(Features::class)
273  ->onlyMethods(['isFeatureEnabled'])
274  ->getMock();
275  $mock->expects(self::any())
276  ->method('isFeatureEnabled')
277  ->with('security.frontend.allowInsecureSiteResolutionByQueryParameters')
278  ->willReturn(false);
279  return $mock;
280  }
281 
282  private function ‪createSiteFinderMock(‪Site ...$sites): ‪SiteFinder
283  {
284  $finderMock = $this
285  ->getMockBuilder(SiteFinder::class)
286  ->onlyMethods(['getAllSites'])
287  ->disableOriginalConstructor()
288  ->getMock();
289  $finderMock->method('getAllSites')->willReturn(array_combine(
290  array_map(static function (‪Site $site) { return $site->‪getIdentifier(); }, $sites),
291  $sites
292  ));
293  return $finderMock;
294  }
295 }
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest\bestMatchingUrlIsUsed
‪bestMatchingUrlIsUsed(string $requestUri, string $expectedSite, string $expectedLocale)
Definition: SiteMatcherTest.php:219
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest\bestMatchingUrlIsUsedDataProvider
‪static bestMatchingUrlIsUsedDataProvider()
Definition: SiteMatcherTest.php:200
‪TYPO3\CMS\Core\Tests\Unit\Routing
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest\createSiteFinderMock
‪createSiteFinderMock(Site ... $sites)
Definition: SiteMatcherTest.php:282
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest\fullUrlMatchesSpecificLanguageWithSubdomainsAndPathSuffixes
‪fullUrlMatchesSpecificLanguageWithSubdomainsAndPathSuffixes()
Definition: SiteMatcherTest.php:126
‪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\Tests\Unit\Routing\SiteMatcherTest\createFeaturesMock
‪createFeaturesMock()
Definition: SiteMatcherTest.php:270
‪TYPO3\CMS\Core\Routing\SiteRouteResult
Definition: SiteRouteResult.php:30
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:56
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:37
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest\fullUrlMatchesSpecificLanguageWithSubdomainsAndDomainSuffixes
‪fullUrlMatchesSpecificLanguageWithSubdomainsAndDomainSuffixes()
Definition: SiteMatcherTest.php:34
‪TYPO3\CMS\Core\Tests\Unit\Routing\SiteMatcherTest
Definition: SiteMatcherTest.php:30
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Routing\SiteMatcher
Definition: SiteMatcher.php:52