[BUGFIX] Fix windows loading of site configuration
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Configuration / SiteConfiguration.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Core\Configuration;
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;
21 use TYPO3\CMS\Core\Cache\CacheManager;
22 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
23 use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
24 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
25 use TYPO3\CMS\Core\Site\Entity\Site;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27
28 /**
29 * Responsibility: Handles the format of the configuration (currently yaml), and the location of the file system folder
30 *
31 * Reads all available site configuration options, and puts them into Site objects.
32 *
33 * @internal
34 */
35 class SiteConfiguration
36 {
37 /**
38 * @var string
39 */
40 protected $configPath;
41
42 /**
43 * Config yaml file name.
44 *
45 * @internal
46 * @var string
47 */
48 protected $configFileName = 'config.yaml';
49
50 /**
51 * Identifier to store all configuration data in cache_core cache.
52 *
53 * @internal
54 * @var string
55 */
56 protected $cacheIdentifier = 'site-configuration';
57
58 /**
59 * @param string $configPath
60 */
61 public function __construct(string $configPath)
62 {
63 $this->configPath = $configPath;
64 }
65
66 /**
67 * Return all site objects which have been found in the filesystem.
68 *
69 * @return Site[]
70 */
71 public function resolveAllExistingSites(): array
72 {
73 // Check if the data is already cached
74 if ($siteConfiguration = $this->getCache()->get($this->cacheIdentifier)) {
75 $siteConfiguration = json_decode($siteConfiguration, true);
76 }
77
78 // Nothing in the cache (or no site found)
79 if (empty($siteConfiguration)) {
80 $finder = new Finder();
81 try {
82 $finder->files()->depth(0)->name($this->configFileName)->in($this->configPath . '/*');
83 } catch (\InvalidArgumentException $e) {
84 // Directory $this->configPath does not exist yet
85 $finder = [];
86 }
87 $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
88 $siteConfiguration = [];
89 foreach ($finder as $fileInfo) {
90 $configuration = $loader->load(GeneralUtility::fixWindowsFilePath((string)$fileInfo));
91 $identifier = basename($fileInfo->getPath());
92 $siteConfiguration[$identifier] = $configuration;
93 }
94 $this->getCache()->set($this->cacheIdentifier, json_encode($siteConfiguration));
95 }
96 $sites = [];
97 foreach ($siteConfiguration ?? [] as $identifier => $configuration) {
98 $rootPageId = (int)($configuration['site']['rootPageId'] ?? 0);
99 if ($rootPageId > 0) {
100 $sites[$identifier] = GeneralUtility::makeInstance(Site::class, $identifier, $rootPageId, $configuration['site']);
101 }
102 }
103 return $sites;
104 }
105
106 /**
107 * Add or update a site configuration
108 *
109 * @param string $siteIdentifier
110 * @param array $configuration
111 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
112 */
113 public function write(string $siteIdentifier, array $configuration): void
114 {
115 $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
116 if (!file_exists($fileName)) {
117 GeneralUtility::mkdir_deep($this->configPath . '/' . $siteIdentifier);
118 }
119 $yamlFileContents = Yaml::dump($configuration, 99, 2);
120 GeneralUtility::writeFile($fileName, $yamlFileContents);
121 $this->getCache()->remove($this->cacheIdentifier);
122 }
123
124 /**
125 * Renames a site identifier (and moves the folder)
126 *
127 * @param string $currentIdentifier
128 * @param string $newIdentifier
129 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
130 */
131 public function rename(string $currentIdentifier, string $newIdentifier): void
132 {
133 $result = rename($this->configPath . '/' . $currentIdentifier, $this->configPath . '/' . $newIdentifier);
134 if (!$result) {
135 throw new \RuntimeException('Unable to rename folder sites/' . $currentIdentifier, 1522491300);
136 }
137 $this->getCache()->remove($this->cacheIdentifier);
138 }
139
140 /**
141 * Removes the config.yaml file of a site configuration.
142 * Also clears the cache.
143 *
144 * @param string $siteIdentifier
145 * @throws SiteNotFoundException
146 */
147 public function delete(string $siteIdentifier): void
148 {
149 $sites = $this->resolveAllExistingSites();
150 if (!isset($sites[$siteIdentifier])) {
151 throw new SiteNotFoundException('Site configuration named ' . $siteIdentifier . ' not found.', 1522866183);
152 }
153 $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
154 if (!file_exists($fileName)) {
155 throw new SiteNotFoundException('Site configuration file ' . $this->configFileName . ' within the site ' . $siteIdentifier . ' not found.', 1522866184);
156 }
157 @unlink($fileName);
158 $this->getCache()->remove($this->cacheIdentifier);
159 }
160
161 /**
162 * Short-hand function for the cache
163 *
164 * @return FrontendInterface
165 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
166 */
167 protected function getCache(): FrontendInterface
168 {
169 return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_core');
170 }
171 }