• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / flux / 30000959906

23 Jul 2026 10:52AM UTC coverage: 89.162% (-3.5%) from 92.657%
30000959906

push

github

NamelessCoder
[TER] 12.0.0

6228 of 6985 relevant lines covered (89.16%)

40.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.51
/Classes/Form/Transformation/FormDataTransformer.php
1
<?php
2
namespace FluidTYPO3\Flux\Form\Transformation;
3

4
/*
5
 * This file is part of the FluidTYPO3/Flux project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10

11
use FluidTYPO3\Flux\Enum\ExtensionOption;
12
use FluidTYPO3\Flux\Enum\FormOption;
13
use FluidTYPO3\Flux\Form;
14
use FluidTYPO3\Flux\Form\ContainerInterface;
15
use FluidTYPO3\Flux\Form\Field;
16
use FluidTYPO3\Flux\Form\Field\Inline\Fal;
17
use FluidTYPO3\Flux\Form\FieldInterface;
18
use FluidTYPO3\Flux\Hooks\HookHandler;
19
use FluidTYPO3\Flux\Utility\ExtensionConfigurationUtility;
20
use TYPO3\CMS\Core\Domain\FlexFormFieldValues;
21
use TYPO3\CMS\Core\Service\FlexFormService;
22

23
class FormDataTransformer
24
{
25
    private FlexFormService $flexFormService;
26
    private DataTransformerRegistry $registry;
27

28
    public function __construct(FlexFormService $flexFormService, DataTransformerRegistry $registry)
29
    {
30
        $this->flexFormService = $flexFormService;
40✔
31
        $this->registry = $registry;
40✔
32
    }
33

34
    /**
35
     * Parses the flexForm content and converts it to an array
36
     * The resulting array will be multi-dimensional, as a value "bla.blubb"
37
     * results in two levels, and a value "bla.blubb.bla" results in three levels.
38
     *
39
     * Note: multi-language flexForms are not supported yet
40
     *
41
     * @param string|FlexFormFieldValues $flexFormContent flexForm xml string or on v14+ instance of FlexFormFieldValues
42
     * @param Form|null $form An instance of \FluidTYPO3\Flux\Form. If transformation instructions are contained in this
43
     *                   configuration they are applied after conversion to array
44
     * @param string|null $languagePointer language pointer used in the flexForm
45
     * @param string|null $valuePointer value pointer used in the flexForm
46
     */
47
    public function convertFlexFormContentToArray(
48
        string|FlexFormFieldValues $flexFormContent,
49
        ?Form $form = null,
50
        ?string $languagePointer = 'lDEF',
51
        ?string $valuePointer = 'vDEF'
52
    ): array {
53
        if (true === empty($flexFormContent)) {
16✔
54
            return [];
4✔
55
        }
56
        if (true === empty($languagePointer)) {
12✔
57
            $languagePointer = 'lDEF';
12✔
58
        }
59
        if (true === empty($valuePointer)) {
12✔
60
            $valuePointer = 'vDEF';
12✔
61
        }
62
        if ($flexFormContent instanceof FlexFormFieldValues) {
12✔
63
            $settings = $flexFormContent->toArray();
8✔
64
        } else {
65
            $settings = $this->flexFormService->convertFlexFormContentToArray(
4✔
66
                $flexFormContent,
4✔
67
                $languagePointer,
4✔
68
                $valuePointer
4✔
69
            );
4✔
70
        }
71

72
        if ($form !== null) {
12✔
73
            if (ExtensionConfigurationUtility::getOption(ExtensionOption::OPTION_UNIQUE_FILE_FIELD_NAMES)) {
10✔
74
                $nestedDimension = $form->getOption(FormOption::RECORD_FIELD);
×
75
                if (isset($settings[$nestedDimension])) {
×
76
                    // Some variables were relocated to a sub-scope. Relocate them back to the root of variables.
77
                    $settings = array_replace_recursive($settings, $settings[$nestedDimension]);
×
78
                    unset($settings[$nestedDimension]);
×
79
                }
80
            }
81
            if ($form->getOption(FormOption::TRANSFORM)) {
10✔
82
                $settings = $this->transformAccordingToConfiguration($settings, $form);
4✔
83
            }
84
        }
85

86
        return $settings;
12✔
87
    }
88

89
    /**
90
     * Transforms members on $values recursively according to the provided
91
     * Flux configuration extracted from a Flux template. Uses "transform"
92
     * attributes on fields to determine how to transform values.
93
     */
94
    public function transformAccordingToConfiguration(array $values, Form $form, string $prefix = ''): array
95
    {
96
        $rebuilt = [];
24✔
97
        foreach ($values as $index => $value) {
24✔
98
            $component = $this->extractTransformableObjectByPath($form, $prefix . $index);
24✔
99
            if (is_array($value)) {
24✔
100
                $value = $this->transformAccordingToConfiguration($value, $form, $prefix . $index . '.');
8✔
101
                if ($object = $this->extractTransformableObjectByPath($form, (string) $index)) {
8✔
102
                    $value = $this->transform($form, $object, $value);
8✔
103
                }
104
            } elseif ($component) {
24✔
105
                $value = $this->transform($form, $component, $value);
20✔
106
            }
107
            if (ExtensionConfigurationUtility::getOption(ExtensionOption::OPTION_UNIQUE_FILE_FIELD_NAMES) &&
24✔
108
                ($component instanceof Fal || ($component instanceof Field && $component->getType() === 'file'))
24✔
109
            ) {
110
                // Revert the field name back to the un-prefixed field name
111
                $index = $component->getName();
×
112
            }
113
            $rebuilt[$index] = $value;
24✔
114
        }
115
        return $rebuilt;
24✔
116
    }
117

118
    /**
119
     * @param mixed $value
120
     * @param FieldInterface|ContainerInterface $object
121
     * @return mixed
122
     */
123
    protected function transform(Form $form, Form\FormInterface $object, $value)
124
    {
125
        $transformType = $object->getTransform();
24✔
126
        if (!$transformType) {
24✔
127
            return $value;
4✔
128
        }
129

130
        $originalValue = $value;
24✔
131
        $value = HookHandler::trigger(
24✔
132
            HookHandler::VALUE_BEFORE_TRANSFORM,
24✔
133
            [
24✔
134
                'value' => $value,
24✔
135
                'object' => $object,
24✔
136
                'type' => $transformType,
24✔
137
                'form' => $form
24✔
138
            ]
24✔
139
        )['value'];
24✔
140
        if ($value === $originalValue) {
24✔
141
            $transformer = $this->registry->resolveDataTransformerByType($transformType);
24✔
142
            $value = $transformer->transform($object, $transformType, $value);
24✔
143
        }
144
        $value = HookHandler::trigger(
24✔
145
            HookHandler::VALUE_AFTER_TRANSFORM,
24✔
146
            [
24✔
147
                'value' => $value,
24✔
148
                'object' => $object,
24✔
149
                'type' => $transformType,
24✔
150
                'form' => $form
24✔
151
            ]
24✔
152
        )['value'];
24✔
153

154
        return $value;
24✔
155
    }
156

157
    /**
158
     * @return FieldInterface|ContainerInterface|null
159
     */
160
    protected function extractTransformableObjectByPath(ContainerInterface $subject, string $path)
161
    {
162
        $pathAsArray = explode('.', $path);
24✔
163
        $subPath = array_shift($pathAsArray);
24✔
164
        $child = null;
24✔
165
        while (count($pathAsArray)) {
24✔
166
            $child = $subject->get($subPath, $subject instanceof Form);
8✔
167
            if ($child) {
8✔
168
                if ($child instanceof Form\Container\Section) {
8✔
169
                    array_shift($pathAsArray);
4✔
170
                }
171
                if ($child instanceof ContainerInterface && count($pathAsArray)) {
8✔
172
                    return $this->extractTransformableObjectByPath($child, implode('.', $pathAsArray));
4✔
173
                }
174
            }
175
            $subPath .= '.' . array_shift($pathAsArray);
8✔
176
        }
177
        /** @var FieldInterface|ContainerInterface $object */
178
        $object = $subject->get($path, true);
24✔
179
        return $object;
24✔
180
    }
181
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc