‪TYPO3CMS  ‪main
FlexFormValueFormatter.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\Backend\Utility\BackendUtility;
25 
34 {
35  protected const ‪VALUE_MAX_LENGTH = 50;
36 
37  public function ‪format(
38  string $tableName,
39  string $fieldName,
40  ?string $value,
41  int ‪$uid,
42  array $fieldConfiguration
43  ): string {
44  if ($value === null || $value === '') {
45  return '';
46  }
47 
48  ‪$record = BackendUtility::getRecord($tableName, ‪$uid) ?? [];
49 
50  // Get FlexForm data and structure
51  $flexFormDataArray = ‪GeneralUtility::xml2array($value);
52  $flexFormDataStructure = $this->‪getFlexFormDataStructure($fieldConfiguration, $tableName, $fieldName, ‪$record);
53 
54  // Map data to FlexForm structure and build an easy to handle array
55  $processedSheets = $this->‪getProcessedSheets($flexFormDataStructure, $flexFormDataArray['data']);
56 
57  // Render a human-readable plain text representation of the FlexForm data
58  $renderedPlainValue = $this->‪renderFlexFormValuePlain($processedSheets);
59  return trim($renderedPlainValue, PHP_EOL);
60  }
61 
69  protected function ‪getFlexFormDataStructure(
70  array $tcaConfiguration,
71  string $tableName,
72  string $fieldName,
73  array ‪$record
74  ): array {
75  $conf['config'] = $tcaConfiguration;
76  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
77  $flexFormIdentifier = $flexFormTools->getDataStructureIdentifier($conf, $tableName, $fieldName, ‪$record);
78  return $flexFormTools->parseDataStructureByIdentifier($flexFormIdentifier);
79  }
80 
86  protected function ‪renderFlexFormValuePlain(array $processedData, int $currentHierarchy = 1): string
87  {
88  $value = '';
89  foreach ($processedData as $processedKey => $processedValue) {
90  $title = !empty($processedValue['section']) ? $processedKey : $processedValue['title'];
91 
92  if (!empty($processedValue['children'])) {
93  $children = $this->‪renderFlexFormValuePlain($processedValue['children'], $currentHierarchy + 1);
94 
95  if (empty($processedValue['section']) && empty($processedValue['container'])) {
96  $value .= $this->‪getSectionHeadline($title) . PHP_EOL . $children . PHP_EOL;
97  } elseif ($children) {
98  $value .= $children . PHP_EOL;
99  }
100  } elseif (isset($processedValue['value'])) {
101  $wrappedValue = $this->‪wrapValue($processedValue['value'], $title);
102  $colon = ':';
103  // Add space after colon, if it fits into one line.
104  if (!str_contains($wrappedValue, PHP_EOL)) {
105  $colon .= ' ';
106  }
107  $value .= $title . $colon . $wrappedValue . PHP_EOL . PHP_EOL;
108  }
109  }
110  return $value;
111  }
112 
116  protected function ‪getSectionHeadline(string $title): string
117  {
118  $sectionSpacer = str_repeat('-', self::VALUE_MAX_LENGTH);
119  return $title . PHP_EOL . $sectionSpacer;
120  }
121 
122  protected function ‪getProcessedSheets(array $dataStructure, array $valueStructure): array
123  {
124  $processedSheets = [];
125 
126  foreach ($dataStructure['sheets'] as $sheetKey => $sheetStructure) {
127  if (!empty($sheetStructure['ROOT']['el'])) {
128  $sheetTitle = $sheetKey;
129  if (!empty($sheetStructure['ROOT']['sheetTitle'])) {
130  $sheetTitle = $this->‪getLanguageService()->sL($sheetStructure['ROOT']['sheetTitle']);
131  }
132 
133  if (!empty($valueStructure[$sheetKey]['lDEF'])) {
134  $processedElements = $this->‪getProcessedElements(
135  $sheetStructure['ROOT']['el'],
136  $valueStructure[$sheetKey]['lDEF']
137  );
138  $processedSheets[$sheetKey] = [
139  'title' => $sheetTitle,
140  'children' => $processedElements,
141  ];
142  }
143  }
144  }
145 
146  return $processedSheets;
147  }
148 
149  protected function ‪getProcessedElements(array $dataStructure, array $valueStructure): array
150  {
151  $processedElements = [];
152 
153  // Values used to fake TCA
154  $processingTableValue = ‪StringUtility::getUniqueId('processing');
155  $processingColumnValue = ‪StringUtility::getUniqueId('processing');
156 
157  foreach ($dataStructure as $elementKey => $elementStructure) {
158  $elementTitle = $this->‪getElementTitle($elementKey, $elementStructure);
159 
160  if (($elementStructure['type'] ?? '') === 'array') {
161  // Render section or container
162  if (empty($valueStructure[$elementKey]['el'])) {
163  continue;
164  }
165 
166  if (!empty($elementStructure['section'])) {
167  // Render section
168  $processedElements[$elementKey] = [
169  'section' => true,
170  'title' => $elementTitle,
171  'children' => $this->‪getProcessedSections(
172  $elementStructure['el'],
173  $valueStructure[$elementKey]['el']
174  ),
175  ];
176  } else {
177  // Render container
178  $processedElements[$elementKey] = [
179  'container' => true,
180  'title' => $elementTitle,
181  'children' => $this->‪getProcessedElements(
182  $elementStructure['el'],
183  $valueStructure[$elementKey]['el']
184  ),
185  ];
186  }
187  } elseif (!empty($elementStructure['config'])) {
188  // Render plain elements
189  $relationTable = $this->‪getRelationTable($elementStructure['config']);
190  $labelUserFunction = $relationTable !== null ? $this->‪getRelationLabelUserFunction($relationTable) : null;
191 
192  if ($relationTable !== null && $labelUserFunction !== null) {
193  $parameters = [
194  'table' => $relationTable,
195  'row' => BackendUtility::getRecord($relationTable, $valueStructure[$elementKey]['vDEF']),
196  'title' => $valueStructure[$elementKey]['vDEF'],
197  ];
198  GeneralUtility::callUserFunction($labelUserFunction, $parameters);
199  $processedValue = $parameters['title'];
200  } else {
201  ‪$GLOBALS['TCA'][$processingTableValue]['columns'][$processingColumnValue]['config'] = $elementStructure['config'];
202  $processedValue = BackendUtility::getProcessedValue(
203  $processingTableValue,
204  $processingColumnValue,
205  $valueStructure[$elementKey]['vDEF'] ?? '',
206  );
207  }
208 
209  $processedElements[$elementKey] = [
210  'title' => $elementTitle,
211  'value' => $processedValue,
212  ];
213  }
214  }
215 
216  if (!empty(‪$GLOBALS['TCA'][$processingTableValue])) {
217  unset(‪$GLOBALS['TCA'][$processingTableValue]);
218  }
219 
220  return $processedElements;
221  }
222 
223  protected function ‪getRelationTable(array $configuration): ?string
224  {
225  // If allowed tables is defined, but with only one(!) table:
226  if (($configuration['allowed'] ?? '') !== '' && !str_contains($configuration['allowed'], ',')) {
227  return $configuration['allowed'];
228  }
229 
230  return $configuration['foreign_table'] ?? null;
231  }
232 
237  protected function ‪getRelationLabelUserFunction(string $relationTable): ?string
238  {
239  if (!empty(‪$GLOBALS['TCA'][$relationTable]['ctrl']['label_userFunc'])) {
240  return ‪$GLOBALS['TCA'][$relationTable]['ctrl']['label_userFunc'];
241  }
242 
243  return null;
244  }
245 
246  protected function ‪getProcessedSections(array $dataStructure, array $valueStructure): array
247  {
248  $processedSections = [];
249 
250  foreach ($valueStructure as $sectionValueIndex => $sectionValueStructure) {
251  $processedSections[$sectionValueIndex] = [
252  'section' => true,
253  'children' => $this->‪getProcessedElements(
254  $dataStructure,
255  $sectionValueStructure
256  ),
257  ];
258  }
259 
260  return $processedSections;
261  }
262 
263  protected function ‪getElementTitle(string $key, array $structure): string
264  {
265  if (!empty($structure['label'])) {
266  return $this->‪getLanguageService()->sL($structure['label']);
267  }
268 
269  return $key;
270  }
271 
272  protected function ‪wrapValue(string $value, string $title): string
273  {
274  if ($value === '') {
275  return '';
276  }
277 
278  // If the length of the value is equal or less than the maxlength, no wrapping is needed.
279  if ((mb_strlen($title) + mb_strlen($value)) <= self::VALUE_MAX_LENGTH) {
280  return $value;
281  }
282 
283  // wordwrap the value and add an indention for each line.
284  $multilineIndention = "\t";
285  $value = PHP_EOL . $multilineIndention . $value;
286  $lines = explode(PHP_EOL, $value);
287  $newValue = '';
288  foreach (array_map(trim(...), $lines) as $line) {
289  if ($line !== '') {
290  $newValue .= PHP_EOL . $line;
291  }
292  }
293  $value = wordwrap($newValue, self::VALUE_MAX_LENGTH, PHP_EOL);
294  return str_replace(PHP_EOL, PHP_EOL . $multilineIndention, $value);
295  }
296 
298  {
299  return ‪$GLOBALS['LANG'];
300  }
301 }
‪TYPO3\CMS\Backend\View\ValueFormatter
Definition: FlexFormValueFormatter.php:18
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\renderFlexFormValuePlain
‪string renderFlexFormValuePlain(array $processedData, int $currentHierarchy=1)
Definition: FlexFormValueFormatter.php:86
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getFlexFormDataStructure
‪array getFlexFormDataStructure(array $tcaConfiguration, string $tableName, string $fieldName, array $record)
Definition: FlexFormValueFormatter.php:69
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getProcessedSections
‪getProcessedSections(array $dataStructure, array $valueStructure)
Definition: FlexFormValueFormatter.php:246
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\wrapValue
‪wrapValue(string $value, string $title)
Definition: FlexFormValueFormatter.php:272
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getRelationLabelUserFunction
‪non empty string null getRelationLabelUserFunction(string $relationTable)
Definition: FlexFormValueFormatter.php:237
‪TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools
Definition: FlexFormTools.php:40
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\format
‪format(string $tableName, string $fieldName, ?string $value, int $uid, array $fieldConfiguration)
Definition: FlexFormValueFormatter.php:37
‪TYPO3\CMS\Webhooks\Message\$record
‪identifier readonly int readonly array $record
Definition: PageModificationMessage.php:36
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\VALUE_MAX_LENGTH
‪const VALUE_MAX_LENGTH
Definition: FlexFormValueFormatter.php:35
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter
Definition: FlexFormValueFormatter.php:34
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getElementTitle
‪getElementTitle(string $key, array $structure)
Definition: FlexFormValueFormatter.php:263
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getRelationTable
‪getRelationTable(array $configuration)
Definition: FlexFormValueFormatter.php:223
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getLanguageService
‪getLanguageService()
Definition: FlexFormValueFormatter.php:297
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getSectionHeadline
‪getSectionHeadline(string $title)
Definition: FlexFormValueFormatter.php:116
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getProcessedElements
‪getProcessedElements(array $dataStructure, array $valueStructure)
Definition: FlexFormValueFormatter.php:149
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Backend\View\ValueFormatter\FlexFormValueFormatter\getProcessedSheets
‪getProcessedSheets(array $dataStructure, array $valueStructure)
Definition: FlexFormValueFormatter.php:122
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility\xml2array
‪static array string xml2array(string $string, string $NSprefix='', bool $reportDocTag=false)
Definition: GeneralUtility.php:1265
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57