getFlexFormDataStructure($fieldConfiguration, $tableName, $fieldName, $record); // Map data to FlexForm structure and build an easy to handle array $processedSheets = $this->getProcessedSheets($flexFormDataStructure, $flexFormDataArray['data'] ?? []); // Render a human-readable plain text representation of the FlexForm data $renderedPlainValue = $this->renderFlexFormValuePlain($processedSheets); return trim($renderedPlainValue, PHP_EOL); } /** * @param array $tcaConfiguration * @param array $record */ protected function getFlexFormDataStructure(array $tcaConfiguration, string $tableName, string $fieldName, array $record): array { $conf['config'] = $tcaConfiguration; $schema = $this->tcaSchemaFactory->get($tableName); return $this->flexFormTools->parseDataStructureByIdentifier( $this->flexFormTools->getDataStructureIdentifier($conf, $tableName, $fieldName, $record, $schema), $schema ); } /** * @param array $processedData */ protected function renderFlexFormValuePlain(array $processedData, int $currentHierarchy = 1): string { $value = ''; foreach ($processedData as $processedKey => $processedValue) { $title = !empty($processedValue['section']) ? $processedKey : $processedValue['title']; if (!empty($processedValue['children'])) { $children = $this->renderFlexFormValuePlain($processedValue['children'], $currentHierarchy + 1); if (empty($processedValue['section']) && empty($processedValue['container'])) { $value .= $this->getSectionHeadline($title) . PHP_EOL . $children . PHP_EOL; } elseif ($children) { $value .= $children . PHP_EOL; } } elseif (isset($processedValue['value'])) { $wrappedValue = $this->wrapValue($processedValue['value'], $title); $colon = ':'; // Add space after colon, if it fits into one line. if (!str_contains($wrappedValue, PHP_EOL)) { $colon .= ' '; } $value .= $title . $colon . $wrappedValue . PHP_EOL . PHP_EOL; } } return $value; } /** * Get the formatted headline of a FlexForm section */ protected function getSectionHeadline(string $title): string { $sectionSpacer = str_repeat('-', self::VALUE_MAX_LENGTH); return $title . PHP_EOL . $sectionSpacer; } protected function getProcessedSheets(array $dataStructure, array $valueStructure): array { $processedSheets = []; foreach ($dataStructure['sheets'] as $sheetKey => $sheetStructure) { if (!empty($sheetStructure['ROOT']['el'])) { $sheetTitle = $sheetKey; if (!empty($sheetStructure['ROOT']['sheetTitle'])) { $sheetTitle = $this->getLanguageService()->sL($sheetStructure['ROOT']['sheetTitle']); } if (!empty($valueStructure[$sheetKey]['lDEF'])) { $processedElements = $this->getProcessedElements($sheetStructure['ROOT']['el'], $valueStructure[$sheetKey]['lDEF']); $processedSheets[$sheetKey] = [ 'title' => $sheetTitle, 'children' => $processedElements, ]; } } } return $processedSheets; } protected function getProcessedElements(array $dataStructure, array $valueStructure): array { $processedElements = []; // Values used to fake TCA $processingTableValue = StringUtility::getUniqueId('processing'); $processingColumnValue = StringUtility::getUniqueId('processing'); foreach ($dataStructure as $elementKey => $elementStructure) { $elementTitle = $this->getElementTitle($elementKey, $elementStructure); if (($elementStructure['type'] ?? '') === 'array') { // Render section or container if (empty($valueStructure[$elementKey]['el'])) { continue; } if (!empty($elementStructure['section'])) { // Render section $processedElements[$elementKey] = [ 'section' => true, 'title' => $elementTitle, 'children' => $this->getProcessedSections( $elementStructure['el'], $valueStructure[$elementKey]['el'] ), ]; } else { // Render container $processedElements[$elementKey] = [ 'container' => true, 'title' => $elementTitle, 'children' => $this->getProcessedElements( $elementStructure['el'], $valueStructure[$elementKey]['el'] ), ]; } } elseif (!empty($elementStructure['config'])) { // Render plain elements $relationTable = $this->getRelationTable($elementStructure['config']) ?? ''; if ($this->tcaSchemaFactory->has($relationTable) && ($userFunc = ($this->tcaSchemaFactory->get($relationTable)->getCapability(TcaSchemaCapability::Label)->getConfiguration()['generator'] ?? false)) ) { $parameters = [ 'table' => $relationTable, 'row' => BackendUtility::getRecord($relationTable, $valueStructure[$elementKey]['vDEF'] ?? ''), 'title' => $valueStructure[$elementKey]['vDEF'] ?? '', 'options' => ($this->tcaSchemaFactory->get($relationTable)->getCapability(TcaSchemaCapability::Label)->getConfiguration()['generatorOptions'] ?? []), ]; GeneralUtility::callUserFunction($userFunc, $parameters); $processedValue = $parameters['title']; } else { $processedValue = BackendUtility::getProcessedValue( $processingTableValue, $processingColumnValue, $valueStructure[$elementKey]['vDEF'] ?? '', 0, false, false, 0, true, 0, [], $elementStructure['config'] ); } $processedElements[$elementKey] = [ 'title' => $elementTitle, 'value' => $processedValue, ]; } } return $processedElements; } protected function getRelationTable(array $configuration): ?string { // If allowed tables is defined, but with only one(!) table: if (($configuration['allowed'] ?? '') !== '' && !str_contains($configuration['allowed'], ',')) { return $configuration['allowed']; } return $configuration['foreign_table'] ?? null; } protected function getProcessedSections(array $dataStructure, array $valueStructure): array { $processedSections = []; foreach ($valueStructure as $sectionValueIndex => $sectionValueStructure) { $processedSections[$sectionValueIndex] = [ 'section' => true, 'children' => $this->getProcessedElements( $dataStructure, $sectionValueStructure ), ]; } return $processedSections; } protected function getElementTitle(string $key, array $structure): string { if (!empty($structure['label'])) { return $this->getLanguageService()->sL($structure['label']); } return $key; } protected function wrapValue(string $value, string $title): string { if ($value === '') { return ''; } // If the length of the value is equal or less than the maxlength, no wrapping is needed. if ((mb_strlen($title) + mb_strlen($value)) <= self::VALUE_MAX_LENGTH) { return $value; } // wordwrap the value and add an indention for each line. $multilineIndention = "\t"; $value = PHP_EOL . $multilineIndention . $value; $lines = explode(PHP_EOL, $value); $newValue = ''; foreach (array_map(trim(...), $lines) as $line) { if ($line !== '') { $newValue .= PHP_EOL . $line; } } $value = wordwrap($newValue, self::VALUE_MAX_LENGTH, PHP_EOL); return str_replace(PHP_EOL, PHP_EOL . $multilineIndention, $value); } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }