‪TYPO3CMS  11.5
LocalConfigurationValueService.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 TYPO3\CMS\Core\Configuration\ConfigurationManager;
27 
35 {
42  public function ‪getCurrentConfigurationData(): array
43  {
44  $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
45  $localConfiguration = $configurationManager->getMergedLocalConfiguration();
46 
47  $data = [];
48  $commentArray = $this->‪getDefaultConfigArrayComments();
49 
50  foreach ($localConfiguration as $sectionName => $section) {
51  if (isset($commentArray[$sectionName])) {
52  $data[$sectionName]['description'] = $commentArray[$sectionName]['description'] ?? $sectionName;
53  $data[$sectionName]['items'] = $this->‪recursiveConfigurationFetching(
54  $section,
55  ‪$GLOBALS['TYPO3_CONF_VARS'][$sectionName] ?? null,
56  $commentArray[$sectionName]
57  );
58  }
59  }
60 
61  ksort($data);
62 
63  return $data;
64  }
65 
76  protected function ‪recursiveConfigurationFetching(array $sections, array $sectionsFromCurrentConfiguration, array $descriptions, array $path = []): array
77  {
78  $data = [];
79 
80  foreach ($sections as $key => $value) {
81  if (!isset($descriptions['items'][$key])) {
82  // @todo should we do something here?
83  continue;
84  }
85 
86  $descriptionInfo = $descriptions['items'][$key];
87  $descriptionType = $descriptionInfo['type'];
88 
89  $newPath = $path;
90  $newPath[] = $key;
91 
92  if ($descriptionType === 'container') {
93  $valueFromCurrentConfiguration = $sectionsFromCurrentConfiguration[$key] ?? null;
94  $data = array_merge($data, $this->‪recursiveConfigurationFetching($value, $valueFromCurrentConfiguration, $descriptionInfo, $newPath));
95  } elseif (!preg_match('/[' . LF . CR . ']/', (string)(is_array($value) ? '' : $value)) || $descriptionType === 'multiline') {
96  $itemData = [];
97  $itemData['key'] = implode('/', $newPath);
98  $itemData['path'] = '[' . implode('][', $newPath) . ']';
99  $itemData['fieldType'] = $descriptionInfo['type'];
100  $itemData['description'] = $descriptionInfo['description'] ?? '';
101  $itemData['readonly'] = $descriptionInfo['readonly'] ?? false;
102  $itemData['allowedValues'] = $descriptionInfo['allowedValues'] ?? [];
103  $itemData['differentValueInCurrentConfiguration'] = (!isset($descriptionInfo['compareValuesWithCurrentConfiguration']) ||
104  $descriptionInfo['compareValuesWithCurrentConfiguration']) &&
105  isset($sectionsFromCurrentConfiguration[$key]) &&
106  $value !== $sectionsFromCurrentConfiguration[$key];
107  switch ($descriptionType) {
108  case 'multiline':
109  $itemData['type'] = 'textarea';
110  $itemData['value'] = str_replace(['\' . LF . \'', '\' . LF . \''], [LF, LF], $value);
111  break;
112  case 'bool':
113  $itemData['type'] = 'checkbox';
114  $itemData['value'] = $value ? '1' : '0';
115  $itemData['checked'] = (bool)$value;
116  break;
117  case 'int':
118  $itemData['type'] = 'number';
119  $itemData['value'] = (int)$value;
120  break;
121  case 'array':
122  $itemData['type'] = 'input';
123  // @todo The line below should be improved when the array handling is introduced in the global settings manager.
124  $itemData['value'] = is_array($value)
125  ? implode(',', $value)
126  : (string)$value;
127  break;
128  // Check if the setting is a PHP error code, will trigger a view helper in fluid
129  case 'errors':
130  $itemData['type'] = 'input';
131  $itemData['value'] = $value;
132  $itemData['phpErrorCode'] = true;
133  break;
134  case 'password':
135  $itemData['type'] = 'password';
136  $itemData['value'] = $value;
137  $itemData['hideValue'] = true;
138  break;
139  default:
140  $itemData['type'] = 'input';
141  $itemData['value'] = $value;
142  }
143 
144  $data[] = $itemData;
145  }
146  }
147 
148  return $data;
149  }
150 
157  public function ‪updateLocalConfigurationValues(array $valueList): ‪FlashMessageQueue
158  {
159  $messageQueue = new ‪FlashMessageQueue('install');
160  $configurationPathValuePairs = [];
161  $commentArray = $this->‪getDefaultConfigArrayComments();
162  $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
163  foreach ($valueList as $path => $value) {
164  try {
165  $oldValue = $configurationManager->getConfigurationValueByPath($path);
166  } catch (‪MissingArrayPathException $e) {
167  $messageQueue->enqueue(new ‪FlashMessage(
168  'Update rejected, the category of this setting does not exist',
169  $path,
171  ));
172  continue;
173  }
174  $pathParts = explode('/', $path);
175  $descriptionData = $commentArray[$pathParts[0]];
176 
177  while ($part = next($pathParts)) {
178  if (!isset($descriptionData['items'][$part])) {
179  $messageQueue->enqueue(new ‪FlashMessage(
180  'Update rejected, this setting is not writable',
181  $path,
183  ));
184  continue 2;
185  }
186  $descriptionData = $descriptionData['items'][$part];
187  }
188 
189  $dataType = $descriptionData['type'];
190 
191  if ($dataType === 'multiline') {
192  $value = str_replace(CR, '', $value);
193  $valueHasChanged = (string)$oldValue !== (string)$value;
194  } elseif ($dataType === 'bool') {
195  // When submitting settings in the Install Tool, values that default to "FALSE" or "TRUE"
196  // in EXT:core/Configuration/DefaultConfiguration.php will be sent as "0" resp. "1".
197  $value = $value === '1';
198  $valueHasChanged = (bool)$oldValue !== $value;
199  } elseif ($dataType === 'int') {
200  // Cast integer values to integers (but only for values that can not contain a string as well)
201  $value = (int)$value;
202  $valueHasChanged = (int)$oldValue !== $value;
203  } elseif ($dataType === 'array') {
204  $oldValueAsString = is_array($oldValue)
205  ? implode(',', $oldValue)
206  : (string)$oldValue;
207  $valueHasChanged = $oldValueAsString !== $value;
208  $value = ‪GeneralUtility::trimExplode(',', $value, true);
209  } else {
210  $valueHasChanged = (string)$oldValue !== (string)$value;
211  }
212 
213  $readonly = $descriptionData['readonly'] ?? false;
214  if ($readonly && $valueHasChanged) {
215  $messageQueue->enqueue(new ‪FlashMessage(
216  'Update rejected, this setting is readonly',
217  $path,
219  ));
220  continue;
221  }
222 
223  // Save if value changed
224  if ($valueHasChanged) {
225  $configurationPathValuePairs[$path] = $value;
226 
227  if (is_bool($value)) {
228  $messageBody = 'New value = ' . ($value ? 'true' : 'false');
229  } elseif (empty($value)) {
230  $messageBody = 'New value = none';
231  } elseif (is_array($value)) {
232  $messageBody = "New value = ['" . implode("', '", $value) . "']";
233  } elseif ($dataType === 'password') {
234  $messageBody = 'New value is set';
235  } else {
236  $messageBody = 'New value = ' . $value;
237  }
238 
239  $messageQueue->enqueue(new ‪FlashMessage(
240  $messageBody,
241  $path
242  ));
243  }
244  }
245  if ($messageQueue->count() > 0) {
246  $configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationPathValuePairs);
247  }
248  return $messageQueue;
249  }
250 
256  protected function ‪getDefaultConfigArrayComments(): array
257  {
258  $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
259  $fileName = $configurationManager->getDefaultConfigurationDescriptionFileLocation();
260  $fileLoader = GeneralUtility::makeInstance(YamlFileLoader::class);
261  return $fileLoader->load($fileName);
262  }
263 }
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Core\Messaging\AbstractMessage
Definition: AbstractMessage.php:26
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Install\Service\LocalConfigurationValueService\getDefaultConfigArrayComments
‪array getDefaultConfigArrayComments()
Definition: LocalConfigurationValueService.php:256
‪TYPO3\CMS\Install\Service\LocalConfigurationValueService\recursiveConfigurationFetching
‪array recursiveConfigurationFetching(array $sections, array $sectionsFromCurrentConfiguration, array $descriptions, array $path=[])
Definition: LocalConfigurationValueService.php:76
‪TYPO3\CMS\Install\Service\LocalConfigurationValueService\updateLocalConfigurationValues
‪FlashMessageQueue updateLocalConfigurationValues(array $valueList)
Definition: LocalConfigurationValueService.php:157
‪TYPO3\CMS\Install\Service\LocalConfigurationValueService\getCurrentConfigurationData
‪array getCurrentConfigurationData()
Definition: LocalConfigurationValueService.php:42
‪TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader
Definition: YamlFileLoader.php:48
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Install\Service\LocalConfigurationValueService
Definition: LocalConfigurationValueService.php:35
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Install\Service
Definition: ClearCacheService.php:16
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:31