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