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

CPS-IT / handlebars-forms / 22343165200

24 Feb 2026 08:40AM UTC coverage: 0.0%. Remained the same
22343165200

push

github

eliashaeussler
[TASK] Rename `ValueProcessor` to `ValueResolver`

0 of 30 new or added lines in 8 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

0 of 484 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/Classes/DataProcessing/ProcessFormProcessor.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "handlebars_forms".
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

18
namespace CPSIT\Typo3HandlebarsForms\DataProcessing;
19

20
use CPSIT\Typo3HandlebarsForms\Domain;
21
use Psr\Http\Message;
22
use Psr\Log;
23
use Symfony\Component\DependencyInjection;
24
use TYPO3\CMS\Fluid;
25
use TYPO3\CMS\Form;
26
use TYPO3\CMS\Frontend;
27
use TYPO3Fluid\Fluid as FluidStandalone;
28

29
/**
30
 * ProcessFormProcessor
31
 *
32
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
33
 * @license GPL-2.0-or-later
34
 */
35
#[DependencyInjection\Attribute\AutoconfigureTag('data.processor', ['identifier' => 'process-form'])]
36
final readonly class ProcessFormProcessor implements Frontend\ContentObject\DataProcessorInterface
37
{
38
    private const CONTENT_PLACEHOLDER = '###FORM_CONTENT###';
39

40
    /**
41
     * @param DependencyInjection\ServiceLocator<Value\ValueResolver> $valueResolvers
42
     */
43
    public function __construct(
×
44
        private Log\LoggerInterface $logger,
45
        private Fluid\Core\Rendering\RenderingContextFactory $renderingContextFactory,
46
        private Domain\Renderable\ViewModel\FormViewModelBuilder $formRenderableProcessor,
47
        #[DependencyInjection\Attribute\AutowireLocator('handlebars_forms.value_resolver', defaultIndexMethod: 'getName')]
48
        private DependencyInjection\ServiceLocator $valueResolvers,
UNCOV
49
    ) {}
×
50

51
    /**
52
     * @param array<string, mixed> $contentObjectConfiguration
53
     * @param array<string, mixed> $processorConfiguration
54
     * @param array<string, mixed> $processedData
55
     * @return array<string, mixed>
56
     */
57
    public function process(
×
58
        Frontend\ContentObject\ContentObjectRenderer $cObj,
59
        array $contentObjectConfiguration,
60
        array $processorConfiguration,
61
        array $processedData,
62
    ): array {
63
        $formRuntime = $contentObjectConfiguration['variables.']['form'] ?? null;
×
64

65
        if (!($formRuntime instanceof Form\Domain\Runtime\FormRuntime)) {
×
66
            $this->logger->error(
×
67
                'Form runtime is not available when trying to process form with plugin uid "{uid}".',
×
68
                ['uid' => $cObj->data['uid'] ?? '(unknown)'],
×
69
            );
×
70

71
            return $processedData;
×
72
        }
73

74
        // Create and prepare Fluid rendering context
75
        $renderingContext = $this->renderingContextFactory->create();
×
76
        $renderingContext->setAttribute(Message\ServerRequestInterface::class, $formRuntime->getRequest());
×
77
        $renderingContext->getViewHelperVariableContainer()->addOrUpdate(
×
78
            Form\ViewHelpers\RenderRenderableViewHelper::class,
×
79
            'formRuntime',
×
80
            $formRuntime,
×
81
        );
×
82

83
        // Render form and process renderables as part of the form's renderChildrenClosure.
84
        // Since the final rendered form content (which especially contains all relevant hidden fields)
85
        // is not yet available when processing renderables, we temporarily pass a content placeholder
86
        // for all configured CONTENT values and replace them with the real content value later.
NEW
87
        $this->formRenderableProcessor->build(
×
88
            $formRuntime,
×
89
            $renderingContext,
×
90
            function (FluidStandalone\Core\ViewHelper\TagBuilder $tagBuilder) use (
×
91
                $cObj,
×
92
                $formRuntime,
×
93
                &$processedData,
×
94
                $processorConfiguration,
×
95
                $renderingContext,
×
96
                &$tag,
×
97
            ) {
×
98
                $tag = $tagBuilder;
×
99
                $tag->setContent(self::CONTENT_PLACEHOLDER);
×
100

NEW
101
                $viewModel = new Domain\Renderable\ViewModel\ViewModel($renderingContext, null, $tag);
×
102
                $processedData = $this->processRenderable($formRuntime, $processorConfiguration, $cObj, $viewModel) ?? [];
×
103

104
                return '';
×
105
            },
×
106
        );
×
107

108
        $formContent = $tag?->getContent();
×
109

110
        // Replace content placeholder with final rendered form content
111
        if ($formContent !== null) {
×
112
            array_walk_recursive($processedData, static function (&$value) use ($formContent) {
×
113
                if (is_string($value)) {
×
114
                    $value = str_replace(self::CONTENT_PLACEHOLDER, $formContent, $value);
×
115
                }
116
            });
×
117
        }
118

119
        return $processedData;
×
120
    }
121

122
    /**
123
     * @param array<string, mixed> $configuration
124
     * @return array<string, mixed>|null
125
     */
126
    private function processRenderable(
×
127
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
128
        array $configuration,
129
        Frontend\ContentObject\ContentObjectRenderer $cObj,
130
        Domain\Renderable\ViewModel\ViewModel $viewModel,
131
    ): ?array {
132
        $processedData = [];
×
133

134
        // Early return on configured "if" condition evaluating to false
135
        if (!$this->checkIf($configuration, $renderable, $cObj, $viewModel)) {
×
136
            return null;
×
137
        }
138

139
        foreach ($configuration as $key => $value) {
×
140
            $keyWithoutDot = rtrim($key, '.');
×
141
            $keyWithDot = $keyWithoutDot . '.';
×
142

143
            if (is_array($value) && !array_key_exists($keyWithoutDot, $processedData)) {
×
NEW
144
                $resolvedValue = $this->processRenderable($renderable, $value, $cObj, $viewModel);
×
145

NEW
146
                if (is_array($resolvedValue)) {
×
NEW
147
                    $processedData[$keyWithoutDot] = $resolvedValue;
×
148
                }
149
            }
150

151
            if (!is_string($value)) {
×
152
                continue;
×
153
            }
154

155
            $valueConfiguration = $configuration[$keyWithDot] ?? [];
×
156

157
            // Resolve configured value
NEW
158
            if ($this->valueResolvers->has($value)) {
×
NEW
159
                $resolvedValue = $this->valueResolvers->get($value)->resolve(
×
160
                    $renderable,
×
161
                    $viewModel,
×
NEW
162
                    new Value\ValueResolutionContext(
×
163
                        $valueConfiguration,
×
164
                        fn(
×
165
                            array $contextConfiguration,
×
166
                            ?Form\Domain\Model\Renderable\RootRenderableInterface $contextRenderable = null,
×
NEW
167
                            ?Domain\Renderable\ViewModel\ViewModel $contextViewModel = null,
×
168
                        ) => $this->processRenderable(
×
169
                            $contextRenderable ?? $renderable,
×
170
                            $contextConfiguration,
×
171
                            $cObj,
×
172
                            $contextViewModel ?? $viewModel,
×
173
                        ),
×
174
                    ),
×
175
                );
×
176
            } else {
NEW
177
                $resolvedValue = $value;
×
178
            }
179

180
            // Skip further processing if processed value is not a string (all COR related methods require a string value)
NEW
181
            if (!is_string($resolvedValue)) {
×
NEW
182
                $processedData[$keyWithoutDot] = $resolvedValue;
×
UNCOV
183
                continue;
×
184
            }
185

186
            // Process value with stdWrap
187
            if (is_array($valueConfiguration['stdWrap.'] ?? null)) {
×
NEW
188
                $resolvedValue = $cObj->stdWrap($resolvedValue, $valueConfiguration['stdWrap.']);
×
189
            }
190

191
            // Skip value if a configured "if" evaluates to false
192
            if (is_array($valueConfiguration['if.'] ?? null)) {
×
NEW
193
                $valueConfiguration['if.']['value'] ??= $resolvedValue;
×
194

195
                if (!$cObj->checkIf($valueConfiguration['if.'])) {
×
196
                    continue;
×
197
                }
198
            }
199

NEW
200
            $processedData[$keyWithoutDot] = $resolvedValue;
×
201
        }
202

203
        return $processedData;
×
204
    }
205

206
    /**
207
     * @param array<string, mixed> $configuration
208
     */
209
    private function checkIf(
×
210
        array &$configuration,
211
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
212
        Frontend\ContentObject\ContentObjectRenderer $cObj,
213
        Domain\Renderable\ViewModel\ViewModel $viewModel,
214
    ): bool {
215
        if (!is_array($configuration['if.'] ?? null)) {
×
216
            return true;
×
217
        }
218

219
        $cObjTemp = clone $cObj;
×
220

221
        if (is_string($configuration['if.']['value'] ?? null) && is_array($configuration['if.']['value.'] ?? null)) {
×
222
            $processedValue = $this->processRenderable(
×
223
                $renderable,
×
224
                [
×
225
                    'value' => $configuration['if.']['value'],
×
226
                    'value.' => $configuration['if.']['value.'],
×
227
                ],
×
228
                $cObj,
×
229
                $viewModel,
×
230
            );
×
231

232
            $cObjTemp->setCurrentVal($processedValue['value'] ?? null);
×
233

234
            unset($configuration['if.']['value'], $configuration['if.']['value.']);
×
235
        }
236

237
        if (!$cObjTemp->checkIf($configuration['if.'])) {
×
238
            return false;
×
239
        }
240

241
        unset($configuration['if.']);
×
242

243
        return true;
×
244
    }
245
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc