fb24580c9bd1efcb7b0f2bbf8531594c2843d5a0
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Site / SiteFinder.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Core\Site;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Core\Environment;
22 use TYPO3\CMS\Core\Exception\Page\PageNotFoundException;
23 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
24 use TYPO3\CMS\Core\Site\Entity\Site;
25 use TYPO3\CMS\Core\Site\Entity\SiteInterface;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Core\Utility\RootlineUtility;
28
29 /**
30 * Is used in backend and frontend for all places where to read / identify sites and site languages.
31 */
32 class SiteFinder
33 {
34 /**
35 * @var Site[]
36 */
37 protected $sites = [];
38
39 /**
40 * Short-hand to quickly fetch a site based on a rootPageId
41 *
42 * @var array
43 */
44 protected $mappingRootPageIdToIdentifier = [];
45
46 /**
47 * Fetches all existing configurations as Site objects
48 */
49 public function __construct()
50 {
51 $reader = GeneralUtility::makeInstance(SiteConfiguration::class, Environment::getConfigPath() . '/sites');
52 $sites = $reader->resolveAllExistingSites();
53 foreach ($sites as $identifier => $site) {
54 $this->sites[$identifier] = $site;
55 $this->mappingRootPageIdToIdentifier[$site->getRootPageId()] = $identifier;
56 }
57 }
58
59 /**
60 * Return a list of all configured sites
61 *
62 * @return Site[]
63 */
64 public function getAllSites(): array
65 {
66 return $this->sites;
67 }
68
69 /**
70 * Get a list of all configured base uris of all sites
71 *
72 * @return array
73 */
74 public function getBaseUris(): array
75 {
76 $baseUrls = [];
77 foreach ($this->sites as $site) {
78 foreach ($site->getLanguages() as $language) {
79 $baseUrls[$language->getBase()] = $language;
80 if ($language->getLanguageId() === 0) {
81 $baseUrls[$site->getBase()] = $language;
82 }
83 }
84 }
85 return $baseUrls;
86 }
87
88 /**
89 * Find a site by given root page id
90 *
91 * @param int $rootPageId
92 * @return SiteInterface
93 * @throws SiteNotFoundException
94 */
95 public function getSiteByRootPageId(int $rootPageId): SiteInterface
96 {
97 if (isset($this->mappingRootPageIdToIdentifier[$rootPageId])) {
98 return $this->sites[$this->mappingRootPageIdToIdentifier[$rootPageId]];
99 }
100 throw new SiteNotFoundException('No site found for root page id ' . $rootPageId, 1521668882);
101 }
102
103 /**
104 * Get a site language by given base URI
105 *
106 * @param string $uri
107 * @return mixed|null
108 */
109 public function getSiteLanguageByBase(string $uri)
110 {
111 $baseUris = $this->getBaseUris();
112 $bestMatchedUri = null;
113 foreach ($baseUris as $base => $language) {
114 if (strpos($uri, $base) === 0 && strlen($bestMatchedUri ?? '') < strlen($base)) {
115 $bestMatchedUri = $base;
116 }
117 }
118 $siteLanguage = $baseUris[$bestMatchedUri] ?? null;
119 if ($siteLanguage instanceof Site) {
120 $siteLanguage = $siteLanguage->getLanguageById(0);
121 }
122 return $siteLanguage;
123 }
124
125 /**
126 * Find a site by given identifier
127 *
128 * @param string $identifier
129 * @return Site
130 * @throws SiteNotFoundException
131 */
132 public function getSiteByIdentifier(string $identifier): Site
133 {
134 if (isset($this->sites[$identifier])) {
135 return $this->sites[$identifier];
136 }
137 throw new SiteNotFoundException('No site found for identifier ' . $identifier, 1521716628);
138 }
139
140 /**
141 * Traverses the rootline of a page up until a Site was found.
142 *
143 * @param int $pageId
144 * @param array $rootLine
145 * @return SiteInterface
146 * @throws SiteNotFoundException
147 */
148 public function getSiteByPageId(int $pageId, array $rootLine = null): SiteInterface
149 {
150 if (!is_array($rootLine)) {
151 try {
152 $rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $pageId)->get();
153 } catch (PageNotFoundException $e) {
154 // Usually when a page was hidden or disconnected
155 // This could be improved by handing in a Context object and decide whether hidden pages
156 // Should be linkeable too
157 $rootLine = [];
158 }
159 }
160 foreach ($rootLine as $pageInRootLine) {
161 if ($pageInRootLine['uid'] > 0) {
162 try {
163 return $this->getSiteByRootPageId((int)$pageInRootLine['uid']);
164 } catch (SiteNotFoundException $e) {
165 // continue looping
166 }
167 }
168 }
169 throw new SiteNotFoundException('No site found in root line of page ' . $pageId, 1521716622);
170 }
171 }