87987c173a1dcbde754b9f42b97622e08e02bcee
[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 $sites = [];
74 $siteConfiguration = $this->getAllSiteConfigurationFromFiles();
75 foreach ($siteConfiguration as $identifier => $configuration) {
76 $rootPageId = (int)($configuration['site']['rootPageId'] ?? 0);
77 if ($rootPageId > 0) {
78 $sites[$identifier] = GeneralUtility::makeInstance(Site::class, $identifier, $rootPageId, $configuration['site']);
79 }
80 }
81 return $sites;
82 }
83
84 /**
85 * Read the site configuration from config files.
86 *
87 * @return array
88 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
89 */
90 protected function getAllSiteConfigurationFromFiles(): array
91 {
92 // Check if the data is already cached
93 if ($siteConfiguration = $this->getCache()->get($this->cacheIdentifier)) {
94 $siteConfiguration = json_decode($siteConfiguration, true);
95 }
96
97 // Nothing in the cache (or no site found)
98 if (empty($siteConfiguration)) {
99 $finder = new Finder();
100 try {
101 $finder->files()->depth(0)->name($this->configFileName)->in($this->configPath . '/*');
102 } catch (\InvalidArgumentException $e) {
103 // Directory $this->configPath does not exist yet
104 $finder = [];
105 }
106 $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
107 $siteConfiguration = [];
108 foreach ($finder as $fileInfo) {
109 $configuration = $loader->load(GeneralUtility::fixWindowsFilePath((string)$fileInfo));
110 $identifier = basename($fileInfo->getPath());
111 $siteConfiguration[$identifier] = $configuration;
112 }
113 $this->getCache()->set($this->cacheIdentifier, json_encode($siteConfiguration));
114 }
115 return $siteConfiguration ?? [];
116 }
117
118 /**
119 * Add or update a site configuration
120 *
121 * @param string $siteIdentifier
122 * @param array $configuration
123 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
124 */
125 public function write(string $siteIdentifier, array $configuration): void
126 {
127 $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
128 if (!file_exists($fileName)) {
129 GeneralUtility::mkdir_deep($this->configPath . '/' . $siteIdentifier);
130 }
131 $yamlFileContents = Yaml::dump($configuration, 99, 2);
132 GeneralUtility::writeFile($fileName, $yamlFileContents);
133 $this->getCache()->remove($this->cacheIdentifier);
134 }
135
136 /**
137 * Renames a site identifier (and moves the folder)
138 *
139 * @param string $currentIdentifier
140 * @param string $newIdentifier
141 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
142 */
143 public function rename(string $currentIdentifier, string $newIdentifier): void
144 {
145 $result = rename($this->configPath . '/' . $currentIdentifier, $this->configPath . '/' . $newIdentifier);
146 if (!$result) {
147 throw new \RuntimeException('Unable to rename folder sites/' . $currentIdentifier, 1522491300);
148 }
149 $this->getCache()->remove($this->cacheIdentifier);
150 }
151
152 /**
153 * Removes the config.yaml file of a site configuration.
154 * Also clears the cache.
155 *
156 * @param string $siteIdentifier
157 * @throws SiteNotFoundException
158 */
159 public function delete(string $siteIdentifier): void
160 {
161 $sites = $this->resolveAllExistingSites();
162 if (!isset($sites[$siteIdentifier])) {
163 throw new SiteNotFoundException('Site configuration named ' . $siteIdentifier . ' not found.', 1522866183);
164 }
165 $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
166 if (!file_exists($fileName)) {
167 throw new SiteNotFoundException('Site configuration file ' . $this->configFileName . ' within the site ' . $siteIdentifier . ' not found.', 1522866184);
168 }
169 @unlink($fileName);
170 $this->getCache()->remove($this->cacheIdentifier);
171 }
172
173 /**
174 * Short-hand function for the cache
175 *
176 * @return FrontendInterface
177 * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
178 */
179 protected function getCache(): FrontendInterface
180 {
181 return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_core');
182 }
183 }