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

CPS-IT / handlebars-forms / 22612356041

03 Mar 2026 07:11AM UTC coverage: 0.0%. Remained the same
22612356041

push

github

eliashaeussler
[FEATURE] Add `VALIDATION_RESULTS` value resolver

0 of 105 new or added lines in 1 file covered. (0.0%)

0 of 612 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/Value/ValidationResultsValueResolver.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\Value;
19

20
use CPSIT\Typo3HandlebarsForms\Domain;
21
use CPSIT\Typo3HandlebarsForms\Fluid;
22
use Psr\Http\Message;
23
use TYPO3\CMS\Extbase;
24
use TYPO3\CMS\Form;
25

26
/**
27
 * ValidationResultsValueResolver
28
 *
29
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
30
 * @license GPL-2.0-or-later
31
 */
32
final readonly class ValidationResultsValueResolver implements ValueResolver
33
{
NEW
34
    public function __construct(
×
35
        private Fluid\ViewHelperInvoker $viewHelperInvoker,
36
    )
37
    {
NEW
38
    }
×
39

NEW
40
    public function resolve(
×
41
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
42
        Domain\Renderable\ViewModel\ViewModel                $viewModel,
43
        ValueResolutionContext                               $context = new ValueResolutionContext(),
44
    ): mixed
45
    {
NEW
46
        $outputInstruction = $context['output'];
×
NEW
47
        $outputConfiguration = $context['output.'];
×
48

49
        // Resolve form definition from renderable
NEW
50
        if ($renderable instanceof Form\Domain\Model\Renderable\AbstractRenderable) {
×
NEW
51
            $property = $renderable->getRootForm()->getIdentifier() . '.' . $renderable->getIdentifier();
×
52
        } else {
NEW
53
            $property = $renderable->getIdentifier();
×
54
        }
55

NEW
56
        $request = $viewModel->renderingContext->getAttribute(Message\ServerRequestInterface::class);
×
NEW
57
        $extbaseRequestParameters = $request->getAttribute('extbase');
×
58

59
        // Early return when resolver was requested outside of extbase context
NEW
60
        if (!($extbaseRequestParameters instanceof Extbase\Mvc\ExtbaseRequestParameters)) {
×
NEW
61
            return null;
×
62
        }
63

NEW
64
        $validationResults = $extbaseRequestParameters->getOriginalRequestMappingResults()->forProperty($property);
×
65

66
        // Normalize output configuration
NEW
67
        if (!is_array($outputConfiguration)) {
×
NEW
68
            $outputConfiguration = null;
×
69
        }
70

71
        // Resolve validation results by a single rendering instruction
NEW
72
        if (is_string($outputInstruction)) {
×
NEW
73
            return $this->processRenderingInstruction(
×
NEW
74
                $renderable,
×
NEW
75
                $viewModel,
×
NEW
76
                $validationResults,
×
NEW
77
                $outputInstruction,
×
NEW
78
                $outputConfiguration ?? [],
×
NEW
79
            );
×
80
        }
81

82
        // Resolve complex rendering configuration
NEW
83
        if (!is_array($outputConfiguration)) {
×
NEW
84
            return $this->processRenderingConfiguration(
×
NEW
85
                $renderable,
×
NEW
86
                $viewModel,
×
NEW
87
                $validationResults,
×
NEW
88
                [],
×
NEW
89
            );
×
90
        }
91

92
        // Return raw results in case no rendering instructions are specified
NEW
93
        return $validationResults;
×
94
    }
95

96
    /**
97
     * @param array<string, mixed> $configuration
98
     * @return array<string, mixed>
99
     */
NEW
100
    private function processRenderingConfiguration(
×
101
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
102
        Domain\Renderable\ViewModel\ViewModel                $viewModel,
103
        Extbase\Error\Result                                 $result,
104
        array                                                $configuration,
105
    ): array
106
    {
NEW
107
        $processedData = [];
×
108

NEW
109
        foreach ($configuration as $key => $value) {
×
NEW
110
            $keyWithoutDot = rtrim($key, '.');
×
NEW
111
            $keyWithDot = $keyWithoutDot . '.';
×
112

NEW
113
            if (is_array($value) && !array_key_exists($keyWithoutDot, $processedData)) {
×
NEW
114
                $processedData[$keyWithoutDot] = $this->processRenderingConfiguration(
×
NEW
115
                    $renderable,
×
NEW
116
                    $viewModel,
×
NEW
117
                    $result,
×
NEW
118
                    $value,
×
NEW
119
                );
×
NEW
120
            } elseif (is_string($value)) {
×
NEW
121
                $processedData[$keyWithoutDot] = $this->processRenderingInstruction(
×
NEW
122
                    $renderable,
×
NEW
123
                    $viewModel,
×
NEW
124
                    $result,
×
NEW
125
                    $value,
×
NEW
126
                    $configuration[$keyWithDot] ?? [],
×
NEW
127
                );
×
128
            }
129
        }
130

NEW
131
        return $processedData;
×
132
    }
133

134
    /**
135
     * @param array<string, mixed> $configuration
136
     */
NEW
137
    private function processRenderingInstruction(
×
138
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
139
        Domain\Renderable\ViewModel\ViewModel                $viewModel,
140
        Extbase\Error\Result                                 $result,
141
        string                                               $value,
142
        array                                                $configuration,
143
    ): mixed
144
    {
NEW
145
        return match ($value) {
×
NEW
146
            'EACH_ERROR' => $this->processErrors($renderable, $viewModel, $result, $configuration),
×
NEW
147
            'ERROR_MESSAGE' => $this->processErrorMessage($renderable, $viewModel, $result),
×
NEW
148
            'PROPERTY' => $this->processProperty($result, $configuration),
×
NEW
149
            default => $value,
×
NEW
150
        };
×
151
    }
152

153
    /**
154
     * @param array<string, mixed> $configuration
155
     * @return ($renderable is Form\Domain\Model\Renderable\CompositeRenderableInterface|Form\Domain\Runtime\FormRuntime ? array<string, list<array<string, mixed>>> : list<array<string, mixed>>)
156
     */
NEW
157
    private function processErrors(
×
158
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
159
        Domain\Renderable\ViewModel\ViewModel                $viewModel,
160
        Extbase\Error\Result                                 $result,
161
        array                                                $configuration,
162
    ): array
163
    {
NEW
164
        $processedErrors = [];
×
165

NEW
166
        foreach ($result->getFlattenedErrors() as $propertyPath => $errors) {
×
NEW
167
            $currentRenderable = $renderable;
×
168

NEW
169
            if ($propertyPath !== '' && $renderable instanceof Form\Domain\Runtime\FormRuntime) {
×
NEW
170
                $currentRenderable = $renderable->getFormDefinition()->getElementByIdentifier($propertyPath);
×
171
            }
172

173
            // Skip errors if current renderable could not be resolved
NEW
174
            if ($currentRenderable === null) {
×
NEW
175
                continue;
×
176
            }
177

NEW
178
            $processedResult = [];
×
179

NEW
180
            foreach ($errors as $error) {
×
NEW
181
                $errorResult = new Extbase\Error\Result();
×
NEW
182
                $errorResult->addError($error);
×
183

NEW
184
                $processedResult[] = $this->processRenderingConfiguration(
×
NEW
185
                    $currentRenderable,
×
NEW
186
                    $viewModel,
×
NEW
187
                    $errorResult,
×
NEW
188
                    $configuration,
×
NEW
189
                );
×
190
            }
191

NEW
192
            $processedErrors[$propertyPath] = $processedResult;
×
193
        }
194

NEW
195
        if ($renderable instanceof Form\Domain\Model\Renderable\CompositeRenderableInterface
×
NEW
196
            || $renderable instanceof Form\Domain\Runtime\FormRuntime
×
197
        ) {
NEW
198
            return $processedErrors;
×
199
        }
200

NEW
201
        $firstProcessedError = reset($processedErrors);
×
202

NEW
203
        if ($firstProcessedError !== false) {
×
NEW
204
            return $firstProcessedError;
×
205
        }
206

NEW
207
        return [];
×
208
    }
209

NEW
210
    private function processErrorMessage(
×
211
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
212
        Domain\Renderable\ViewModel\ViewModel                $viewModel,
213
        Extbase\Error\Result                                 $result,
214
    ): mixed
215
    {
NEW
216
        $error = $result->getFirstError();
×
217

218
        // Early return if no error is attached to result
NEW
219
        if ($error === false) {
×
NEW
220
            return null;
×
221
        }
222

NEW
223
        $translationResult = $this->viewHelperInvoker->invoke(
×
NEW
224
            $viewModel->renderingContext,
×
NEW
225
            Form\ViewHelpers\TranslateElementErrorViewHelper::class,
×
NEW
226
            [
×
NEW
227
                'element' => $renderable,
×
NEW
228
                'error' => $error,
×
NEW
229
            ],
×
NEW
230
        );
×
231

NEW
232
        return $translationResult->content;
×
233
    }
234

235
    /**
236
     * @param array<string, mixed> $configuration
237
     */
NEW
238
    private function processProperty(Extbase\Error\Result $result, array $configuration): mixed
×
239
    {
NEW
240
        $path = $configuration['path'] ?? null;
×
241

NEW
242
        if (!is_string($path)) {
×
NEW
243
            return null;
×
244
        }
245

NEW
246
        return Extbase\Reflection\ObjectAccess::getProperty($result, $path);
×
247
    }
248

NEW
249
    public static function getName(): string
×
250
    {
NEW
251
        return 'VALIDATION_RESULTS';
×
252
    }
253
}
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