‪TYPO3CMS  10.4
Site.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 Psr\Http\Message\UriInterface;
21 use Symfony\Component\ExpressionLanguage\SyntaxError;
35 
39 class ‪Site implements ‪SiteInterface
40 {
41  protected const ‪ERRORHANDLER_TYPE_PAGE = 'Page';
42  protected const ‪ERRORHANDLER_TYPE_FLUID = 'Fluid';
43  protected const ‪ERRORHANDLER_TYPE_PHP = 'PHP';
44 
48  protected ‪$identifier;
49 
53  protected ‪$base;
54 
58  protected ‪$rootPageId;
59 
64  protected ‪$configuration;
65 
69  protected ‪$languages;
70 
74  protected ‪$errorHandlers;
75 
83  public function ‪__construct(string ‪$identifier, int ‪$rootPageId, array ‪$configuration)
84  {
85  $this->identifier = ‪$identifier;
86  $this->rootPageId = ‪$rootPageId;
87  $this->configuration = ‪$configuration;
88  ‪$configuration['languages'] = !empty(‪$configuration['languages']) ? ‪$configuration['languages'] : [
89  0 => [
90  'languageId' => 0,
91  'title' => 'Default',
92  'navigationTitle' => '',
93  'typo3Language' => 'default',
94  'flag' => 'us',
95  'locale' => 'en_US.UTF-8',
96  'iso-639-1' => 'en',
97  'hreflang' => 'en-US',
98  'direction' => '',
99  ]
100  ];
101  $baseUrl = $this->‪resolveBaseWithVariants(
102  $configuration['base'] ?? '',
103  ‪$configuration['baseVariants'] ?? null
104  );
105  $this->base = new ‪Uri($this->‪sanitizeBaseUrl($baseUrl));
106 
107  foreach (‪$configuration['languages'] as $languageConfiguration) {
108  $languageUid = (int)$languageConfiguration['languageId'];
109  // site language has defined its own base, this is the case most of the time.
110  if (!empty($languageConfiguration['base'])) {
112  $languageConfiguration['base'],
113  $languageConfiguration['baseVariants'] ?? null
114  );
116  // no host given by the language-specific base, so lets prefix the main site base
117  if (‪$base->getScheme() === '' && ‪$base->getHost() === '') {
118  ‪$base = rtrim((string)$this->base, '/') . '/' . ltrim((string)‪$base, '/');
119  ‪$base = new ‪Uri($this->‪sanitizeBaseUrl($base));
120  }
121  } else {
122  // Language configuration does not have a base defined
123  // So the main site base is used (usually done for default languages)
124  ‪$base = new ‪Uri($this->‪sanitizeBaseUrl(rtrim((string)$this->base, '/') . '/'));
125  }
126  if (!empty($languageConfiguration['flag'])) {
127  if ($languageConfiguration['flag'] === 'global') {
128  $languageConfiguration['flag'] = 'flags-multiple';
129  } elseif ($languageConfiguration['flag'] !== 'empty-empty') {
130  $languageConfiguration['flag'] = 'flags-' . $languageConfiguration['flag'];
131  }
132  }
133  $this->languages[$languageUid] = new ‪SiteLanguage(
134  $languageUid,
135  $languageConfiguration['locale'],
136  ‪$base,
137  $languageConfiguration
138  );
139  }
140  foreach (‪$configuration['errorHandling'] ?? [] as $errorHandlingConfiguration) {
141  $code = $errorHandlingConfiguration['errorCode'];
142  unset($errorHandlingConfiguration['errorCode']);
143  $this->errorHandlers[(int)$code] = $errorHandlingConfiguration;
144  }
145  }
146 
154  protected function ‪resolveBaseWithVariants(string $baseUrl, ?array $baseVariants): string
155  {
156  if (!empty($baseVariants)) {
157  $expressionLanguageResolver = GeneralUtility::makeInstance(
158  Resolver::class,
159  'site',
160  []
161  );
162  foreach ($baseVariants as $baseVariant) {
163  try {
164  if ($expressionLanguageResolver->evaluate($baseVariant['condition'])) {
165  $baseUrl = $baseVariant['base'];
166  break;
167  }
168  } catch (SyntaxError $e) {
169  // silently fail and do not evaluate
170  // no logger here, as Site is currently cached and serialized
171  }
172  }
173  }
174  return $baseUrl;
175  }
176 
183  public function ‪getIdentifier(): string
184  {
185  return ‪$this->identifier;
186  }
187 
193  public function ‪getBase(): UriInterface
194  {
195  return ‪$this->base;
196  }
197 
203  public function ‪getRootPageId(): int
204  {
205  return ‪$this->rootPageId;
206  }
207 
213  public function ‪getLanguages(): array
214  {
215  ‪$languages = [];
216  foreach ($this->languages as $languageId => $language) {
217  if ($language->enabled()) {
218  ‪$languages[$languageId] = $language;
219  }
220  }
221  return ‪$languages;
222  }
223 
229  public function ‪getAllLanguages(): array
230  {
231  return ‪$this->languages;
232  }
233 
241  public function ‪getLanguageById(int $languageId): ‪SiteLanguage
242  {
243  if (isset($this->languages[$languageId])) {
244  return $this->languages[$languageId];
245  }
246  throw new \InvalidArgumentException(
247  'Language ' . $languageId . ' does not exist on site ' . $this->identifier . '.',
248  1522960188
249  );
250  }
251 
255  public function ‪getDefaultLanguage(): ‪SiteLanguage
256  {
257  return reset($this->languages);
258  }
259 
263  public function ‪getAvailableLanguages(‪BackendUserAuthentication $user, bool $includeAllLanguagesFlag = false, int $pageId = null): array
264  {
265  $availableLanguages = [];
266 
267  // Check if we need to add language "-1"
268  if ($includeAllLanguagesFlag && $user->‪checkLanguageAccess(-1)) {
269  $availableLanguages[-1] = new ‪SiteLanguage(-1, '', $this->‪getBase(), [
270  'title' => $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:multipleLanguages'),
271  'flag' => 'flags-multiple'
272  ]);
273  }
274 
275  // Do not add the ones that are not allowed by the user
276  foreach ($this->languages as $language) {
277  if ($user->‪checkLanguageAccess($language->getLanguageId())) {
278  $availableLanguages[$language->getLanguageId()] = $language;
279  }
280  }
281 
282  return $availableLanguages;
283  }
284 
293  public function ‪getErrorHandler(int $statusCode): PageErrorHandlerInterface
294  {
295  $errorHandlerConfiguration = $this->errorHandlers[$statusCode] ?? null;
296  switch ($errorHandlerConfiguration['errorHandler'] ?? null) {
298  return GeneralUtility::makeInstance(FluidPageErrorHandler::class, $statusCode, $errorHandlerConfiguration);
300  return GeneralUtility::makeInstance(PageContentErrorHandler::class, $statusCode, $errorHandlerConfiguration);
302  $handler = GeneralUtility::makeInstance($errorHandlerConfiguration['errorPhpClassFQCN'], $statusCode, $errorHandlerConfiguration);
303  // Check if the interface is implemented
304  if (!($handler instanceof PageErrorHandlerInterface)) {
305  throw new InvalidPageErrorHandlerException('The configured error handler "' . (string)$errorHandlerConfiguration['errorPhpClassFQCN'] . '" for status code ' . $statusCode . ' must implement the PageErrorHandlerInterface.', 1527432330);
306  }
307  return $handler;
308  }
309  throw new PageErrorHandlerNotConfiguredException('No error handler given for the status code "' . $statusCode . '".', 1522495914);
310  }
311 
317  public function ‪getConfiguration(): array
318  {
320  }
321 
329  public function ‪getAttribute(string $attributeName)
330  {
331  if (isset($this->configuration[$attributeName])) {
332  return $this->configuration[$attributeName];
333  }
334  throw new \InvalidArgumentException(
335  'Attribute ' . $attributeName . ' does not exist on site ' . $this->identifier . '.',
336  1522495954
337  );
338  }
339 
347  protected function ‪sanitizeBaseUrl(string ‪$base): string
348  {
349  // no protocol ("//") and the first part is no "/" (path), means that this is a domain like
350  // "www.domain.com/subpage", and we want to ensure that this one then gets a "no-scheme agnostic" part
351  if (!empty(‪$base) && strpos(‪$base, '//') === false && ‪$base[0] !== '/') {
352  // either a scheme is added, or no scheme but with domain, or a path which is not absolute
353  // make the base prefixed with a slash, so it is recognized as path, not as domain
354  // treat as path
355  if (strpos(‪$base, '.') === false) {
356  ‪$base = '/' . ‪$base;
357  } else {
358  // treat as domain name
359  ‪$base = '//' . ‪$base;
360  }
361  }
362  return ‪$base;
363  }
364 
371  public function ‪getRouter(Context $context = null): RouterInterface
372  {
373  return GeneralUtility::makeInstance(PageRouter::class, $this, $context);
374  }
375 
380  protected function ‪getLanguageService(): ‪LanguageService
381  {
382  return ‪$GLOBALS['LANG'];
383  }
384 }
‪TYPO3\CMS\Core\Site\Entity\SiteInterface
Definition: SiteInterface.php:26
‪TYPO3\CMS\Core\Routing\RouterInterface
Definition: RouterInterface.php:28
‪TYPO3\CMS\Core\Site\Entity\Site\getLanguageById
‪SiteLanguage getLanguageById(int $languageId)
Definition: Site.php:235
‪TYPO3\CMS\Core\Site\Entity\Site\getLanguageService
‪LanguageService getLanguageService()
Definition: Site.php:374
‪TYPO3\CMS\Core\Site\Entity\Site\getLanguages
‪SiteLanguage[] getLanguages()
Definition: Site.php:207
‪TYPO3\CMS\Core\Site\Entity\Site\getRouter
‪RouterInterface getRouter(Context $context=null)
Definition: Site.php:365
‪TYPO3\CMS\Core\Site\Entity\Site\getAttribute
‪mixed getAttribute(string $attributeName)
Definition: Site.php:323
‪TYPO3\CMS\Core\Site\Entity\Site\getErrorHandler
‪PageErrorHandlerInterface getErrorHandler(int $statusCode)
Definition: Site.php:287
‪TYPO3\CMS\Core\Error\PageErrorHandler\FluidPageErrorHandler
Definition: FluidPageErrorHandler.php:32
‪TYPO3\CMS\Core\Routing\PageRouter
Definition: PageRouter.php:71
‪TYPO3\CMS\Core\Site\Entity\Site\ERRORHANDLER_TYPE_PAGE
‪const ERRORHANDLER_TYPE_PAGE
Definition: Site.php:41
‪TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerNotConfiguredException
Definition: PageErrorHandlerNotConfiguredException.php:27
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Site\Entity\Site\getConfiguration
‪array getConfiguration()
Definition: Site.php:311
‪TYPO3\CMS\Core\Http\Uri
Definition: Uri.php:29
‪TYPO3\CMS\Core\Error\PageErrorHandler\InvalidPageErrorHandlerException
Definition: InvalidPageErrorHandlerException.php:27
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:40
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Core\Site\Entity\Site\getAvailableLanguages
‪getAvailableLanguages(BackendUserAuthentication $user, bool $includeAllLanguagesFlag=false, int $pageId=null)
Definition: Site.php:257
‪TYPO3\CMS\Core\Site\Entity\Site\getIdentifier
‪string getIdentifier()
Definition: Site.php:177
‪TYPO3\CMS\Core\Site\Entity\Site\$identifier
‪string $identifier
Definition: Site.php:47
‪TYPO3\CMS\Core\Site\Entity\Site\$rootPageId
‪int $rootPageId
Definition: Site.php:55
‪TYPO3\CMS\Core\Site\Entity\Site\ERRORHANDLER_TYPE_FLUID
‪const ERRORHANDLER_TYPE_FLUID
Definition: Site.php:42
‪TYPO3\CMS\Core\Site\Entity\Site\ERRORHANDLER_TYPE_PHP
‪const ERRORHANDLER_TYPE_PHP
Definition: Site.php:43
‪TYPO3\CMS\Core\Error\PageErrorHandler\PageContentErrorHandler
Definition: PageContentErrorHandler.php:43
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\checkLanguageAccess
‪bool checkLanguageAccess($langValue)
Definition: BackendUserAuthentication.php:709
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Site\Entity\Site\$languages
‪SiteLanguage[] $languages
Definition: Site.php:64
‪TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface
Definition: PageErrorHandlerInterface.php:29
‪TYPO3\CMS\Core\Site\Entity\Site\getBase
‪UriInterface getBase()
Definition: Site.php:187
‪TYPO3\CMS\Core\Site\Entity\Site\getAllLanguages
‪SiteLanguage[] getAllLanguages()
Definition: Site.php:223
‪TYPO3\CMS\Core\Site\Entity\Site\sanitizeBaseUrl
‪string sanitizeBaseUrl(string $base)
Definition: Site.php:341
‪TYPO3\CMS\Core\Site\Entity
Definition: NullSite.php:18
‪TYPO3\CMS\Core\Site\Entity\Site\$configuration
‪array $configuration
Definition: Site.php:60
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:27
‪TYPO3\CMS\Core\Site\Entity\Site\getRootPageId
‪int getRootPageId()
Definition: Site.php:197
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Site\Entity\Site\getDefaultLanguage
‪getDefaultLanguage()
Definition: Site.php:249
‪TYPO3\CMS\Core\Site\Entity\Site\resolveBaseWithVariants
‪string resolveBaseWithVariants(string $baseUrl, ?array $baseVariants)
Definition: Site.php:148
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Site\Entity\Site\$base
‪UriInterface $base
Definition: Site.php:51
‪TYPO3\CMS\Core\Site\Entity\Site\$errorHandlers
‪array $errorHandlers
Definition: Site.php:68
‪TYPO3\CMS\Core\Site\Entity\Site\__construct
‪__construct(string $identifier, int $rootPageId, array $configuration)
Definition: Site.php:77