‪TYPO3CMS  9.5
SiteConfiguration.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
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 Symfony\Component\Finder\Finder;
20 use Symfony\Component\Yaml\Yaml;
29 
38 {
42  protected ‪$configPath;
43 
50  protected ‪$configFileName = 'config.yaml';
51 
58  protected ‪$cacheIdentifier = 'site-configuration';
59 
66  protected ‪$firstLevelCache;
67 
71  public function ‪__construct(string ‪$configPath)
72  {
73  $this->configPath = ‪$configPath;
74  }
75 
82  public function ‪getAllExistingSites(bool $useCache = true): array
83  {
84  if ($useCache && $this->firstLevelCache !== null) {
86  }
87  return $this->‪resolveAllExistingSites($useCache);
88  }
89 
95  public function ‪resolveAllExistingSites(): array
96  {
97  $sites = [];
98  $siteConfiguration = $this->‪getAllSiteConfigurationFromFiles();
99  foreach ($siteConfiguration as $identifier => $configuration) {
100  $rootPageId = (int)($configuration['rootPageId'] ?? 0);
101  if ($rootPageId > 0) {
102  $sites[$identifier] = GeneralUtility::makeInstance(Site::class, $identifier, $rootPageId, $configuration);
103  }
104  }
105  $this->firstLevelCache = $sites;
106  return $sites;
107  }
108 
115  protected function ‪getAllSiteConfigurationFromFiles(): array
116  {
117  // Check if the data is already cached
118  if ($siteConfiguration = $this->‪getCache()->get($this->cacheIdentifier)) {
119  // Due to the nature of PhpFrontend, the `<?php` and `#` wraps have to be removed
120  $siteConfiguration = preg_replace('/^<\?php\s*|\s*#$/', '', $siteConfiguration);
121  $siteConfiguration = json_decode($siteConfiguration, true);
122  }
123 
124  // Nothing in the cache (or no site found)
125  if (empty($siteConfiguration)) {
126  ‪$finder = new Finder();
127  try {
128  ‪$finder->files()->depth(0)->name($this->configFileName)->in($this->configPath . '/*');
129  } catch (\InvalidArgumentException $e) {
130  // Directory $this->configPath does not exist yet
131  ‪$finder = [];
132  }
133  $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
134  $siteConfiguration = [];
135  foreach (‪$finder as $fileInfo) {
136  $configuration = $loader->load(GeneralUtility::fixWindowsFilePath((string)$fileInfo));
137  $identifier = basename($fileInfo->getPath());
138  if (isset($configuration['site'])) {
139  trigger_error(
140  'Site configuration with key \'site\' has been deprecated, remove indentation level and site key.',
141  E_USER_DEPRECATED
142  );
143  $configuration = $configuration['site'];
144  }
145  $siteConfiguration[$identifier] = $configuration;
146  }
147  $this->‪getCache()->‪set($this->cacheIdentifier, json_encode($siteConfiguration));
148  }
149  return $siteConfiguration ?? [];
150  }
151 
162  public function ‪load(string $siteIdentifier): array
163  {
164  $fileName = $this->configPath . '/' . $siteIdentifier . '/' . ‪$this->configFileName;
165  $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
166  return $loader->load(GeneralUtility::fixWindowsFilePath($fileName), ‪YamlFileLoader::PROCESS_IMPORTS);
167  }
168 
176  public function ‪write(string $siteIdentifier, array $configuration): void
177  {
178  $folder = $this->configPath . '/' . $siteIdentifier;
179  $fileName = $folder . '/' . ‪$this->configFileName;
180  $newConfiguration = $configuration;
181  if (!file_exists($folder)) {
182  GeneralUtility::mkdir_deep($folder);
183  } elseif (file_exists($fileName)) {
184  $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
185  // load without any processing to have the unprocessed base to modify
186  $newConfiguration = $loader->load(GeneralUtility::fixWindowsFilePath($fileName), 0);
187  // load the processed configuration to diff changed values
188  $processed = $loader->load(GeneralUtility::fixWindowsFilePath($fileName));
189  // find properties that were modified via GUI
190  $newModified = array_replace_recursive(
191  self::findRemoved($processed, $configuration),
192  self::findModified($processed, $configuration)
193  );
194  // change _only_ the modified keys, leave the original non-changed areas alone
195  ‪ArrayUtility::mergeRecursiveWithOverrule($newConfiguration, $newModified);
196  }
197  $newConfiguration = $this->‪sortConfiguration($newConfiguration);
198  $yamlFileContents = Yaml::dump($newConfiguration, 99, 2);
199  GeneralUtility::writeFile($fileName, $yamlFileContents);
200  $this->firstLevelCache = null;
201  $this->‪getCache()->‪remove($this->cacheIdentifier);
202  $this->‪getCache()->‪remove('pseudo-sites');
203  }
204 
212  public function ‪rename(string $currentIdentifier, string $newIdentifier): void
213  {
214  $result = ‪rename($this->configPath . '/' . $currentIdentifier, $this->configPath . '/' . $newIdentifier);
215  if (!$result) {
216  throw new \RuntimeException('Unable to rename folder sites/' . $currentIdentifier, 1522491300);
217  }
218  $this->‪getCache()->‪remove($this->cacheIdentifier);
219  $this->firstLevelCache = null;
220  }
221 
229  public function delete(string $siteIdentifier): void
230  {
231  $sites = $this->‪getAllExistingSites();
232  if (!isset($sites[$siteIdentifier])) {
233  throw new SiteNotFoundException('Site configuration named ' . $siteIdentifier . ' not found.', 1522866183);
234  }
235  $fileName = $this->configPath . '/' . $siteIdentifier . '/' . ‪$this->configFileName;
236  if (!file_exists($fileName)) {
237  throw new SiteNotFoundException('Site configuration file ' . $this->configFileName . ' within the site ' . $siteIdentifier . ' not found.', 1522866184);
238  }
239  @unlink($fileName);
240  $this->‪getCache()->‪remove($this->cacheIdentifier);
241  $this->‪getCache()->‪remove('pseudo-sites');
242  $this->firstLevelCache = null;
243  }
244 
251  protected function ‪getCache(): FrontendInterface
252  {
253  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_core');
254  }
255 
260  protected function ‪sortConfiguration(array $newConfiguration): array
261  {
262  ksort($newConfiguration);
263  if (isset($newConfiguration['imports'])) {
264  $imports = $newConfiguration['imports'];
265  unset($newConfiguration['imports']);
266  $newConfiguration['imports'] = $imports;
267  }
268  return $newConfiguration;
269  }
270 
271  protected static function ‪findModified(array $currentConfiguration, array $newConfiguration): array
272  {
273  $differences = [];
274  foreach ($newConfiguration as $key => $value) {
275  if (!isset($currentConfiguration[$key]) || $currentConfiguration[$key] !== $newConfiguration[$key]) {
276  if (!isset($newConfiguration[$key]) && isset($currentConfiguration[$key])) {
277  $differences[$key] = '__UNSET';
278  } elseif (isset($currentConfiguration[$key])
279  && is_array($newConfiguration[$key])
280  && is_array($currentConfiguration[$key])
281  ) {
282  $differences[$key] = ‪self::findModified($currentConfiguration[$key], $newConfiguration[$key]);
283  } else {
284  $differences[$key] = $value;
285  }
286  }
287  }
288  return $differences;
289  }
290 
291  protected static function ‪findRemoved(array $currentConfiguration, array $newConfiguration): array
292  {
293  $removed = [];
294  foreach ($currentConfiguration as $key => $value) {
295  if (!isset($newConfiguration[$key])) {
296  $removed[$key] = '__UNSET';
297  } elseif (isset($currentConfiguration[$key]) && is_array($currentConfiguration[$key]) && is_array($newConfiguration[$key])) {
298  $removedInRecursion = ‪self::findRemoved($currentConfiguration[$key], $newConfiguration[$key]);
299  if (!empty($removedInRecursion)) {
300  $removed[$key] = $removedInRecursion;
301  }
302  }
303  }
304 
305  return $removed;
306  }
307 }
‪TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader\PROCESS_IMPORTS
‪const PROCESS_IMPORTS
Definition: YamlFileLoader.php:45
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\getAllExistingSites
‪Site[] getAllExistingSites(bool $useCache=true)
Definition: SiteConfiguration.php:78
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\findRemoved
‪static findRemoved(array $currentConfiguration, array $newConfiguration)
Definition: SiteConfiguration.php:287
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\resolveAllExistingSites
‪Site[] resolveAllExistingSites()
Definition: SiteConfiguration.php:91
‪$finder
‪$finder
Definition: annotationChecker.php:102
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\rename
‪rename(string $currentIdentifier, string $newIdentifier)
Definition: SiteConfiguration.php:208
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:25
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:614
‪TYPO3\CMS\Core\Configuration\SiteConfiguration
Definition: SiteConfiguration.php:38
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\sortConfiguration
‪array sortConfiguration(array $newConfiguration)
Definition: SiteConfiguration.php:256
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\__construct
‪__construct(string $configPath)
Definition: SiteConfiguration.php:67
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:39
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\$firstLevelCache
‪array null $firstLevelCache
Definition: SiteConfiguration.php:62
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\$configFileName
‪string $configFileName
Definition: SiteConfiguration.php:48
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\$configPath
‪string $configPath
Definition: SiteConfiguration.php:41
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\load
‪array load(string $siteIdentifier)
Definition: SiteConfiguration.php:158
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\getAllSiteConfigurationFromFiles
‪array getAllSiteConfigurationFromFiles()
Definition: SiteConfiguration.php:111
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\$cacheIdentifier
‪string $cacheIdentifier
Definition: SiteConfiguration.php:55
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:21
‪TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader
Definition: YamlFileLoader.php:41
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪TYPO3\CMS\Core\Configuration
Definition: ConfigurationManager.php:2
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\findModified
‪static findModified(array $currentConfiguration, array $newConfiguration)
Definition: SiteConfiguration.php:267
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface\remove
‪bool remove($entryIdentifier)
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface\set
‪set($entryIdentifier, $data, array $tags=[], $lifetime=null)
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\getCache
‪FrontendInterface getCache()
Definition: SiteConfiguration.php:247
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Configuration\SiteConfiguration\write
‪write(string $siteIdentifier, array $configuration)
Definition: SiteConfiguration.php:172