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

CPS-IT / handlebars-forms / 26559579792

28 May 2026 06:52AM UTC coverage: 0.52% (-0.02%) from 0.538%
26559579792

Pull #42

github

web-flow
Merge 9b7a3a181 into a24db9204
Pull Request #42: [!!!][FEATURE] Support `multiple` attribute in `FileUpload` element

0 of 61 new or added lines in 2 files covered. (0.0%)

3 existing lines in 1 file now uncovered.

7 of 1347 relevant lines covered (0.52%)

0.02 hits per line

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

0.0
/Classes/Domain/ViewModel/Builder/FileUploadViewModelBuilder.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\Domain\ViewModel\Builder;
19

20
use CPSIT\Typo3HandlebarsForms\Domain;
21
use CPSIT\Typo3HandlebarsForms\Fluid\ViewHelperInvoker;
22
use TYPO3\CMS\Core;
23
use TYPO3\CMS\Extbase;
24
use TYPO3\CMS\Fluid;
25
use TYPO3\CMS\Form;
26
use TYPO3Fluid\Fluid as FluidStandalone;
27

28
/**
29
 * FileUploadViewModelBuilder
30
 *
31
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
32
 * @license GPL-2.0-or-later
33
 *
34
 * @extends AbstractViewModelBuilder<Form\Domain\Model\FormElements\FileUpload>
35
 */
36
final class FileUploadViewModelBuilder extends AbstractViewModelBuilder
37
{
38
    protected array $supportedTypes = [
39
        'FileUpload',
40
        'ImageUpload',
41
    ];
42

43
    private readonly Core\Information\Typo3Version $typo3Version;
44

NEW
45
    public function __construct(ViewHelperInvoker $viewHelperInvoker)
×
46
    {
NEW
47
        parent::__construct($viewHelperInvoker);
×
48

NEW
49
        $this->typo3Version = new Core\Information\Typo3Version();
×
50
    }
51

UNCOV
52
    public function renderRenderable(
×
53
        Form\Domain\Model\Renderable\RootRenderableInterface $renderable,
54
        Fluid\Core\Rendering\RenderingContext $renderingContext,
55
    ): Domain\ViewModel\ViewModelCollection|Domain\ViewModel\ViewHelperContainedViewModel {
56
        $resource = null;
×
57
        $resourceVariableName = 'resource';
×
NEW
58
        $arguments = [
×
NEW
59
            'property' => $renderable->getIdentifier(),
×
NEW
60
            'as' => $resourceVariableName,
×
NEW
61
            'id' => $renderable->getUniqueIdentifier(),
×
NEW
62
            'class' => $renderable->getProperties()['elementClassAttribute'] ?? null,
×
NEW
63
            'errorClass' => $renderable->getProperties()['elementErrorClassAttribute'] ?? null,
×
NEW
64
            'additionalAttributes' => $this->renderAdditionalAttributes($renderable, $renderingContext),
×
NEW
65
            'accept' => $renderable->getProperties()['allowedMimeTypes'] ?? null,
×
NEW
66
        ];
×
67

68
        // @todo Remove condition once support for TYPO3 v13 is dropped
NEW
69
        if ($this->typo3Version->getMajorVersion() >= 14) {
×
NEW
70
            $arguments['multiple'] = $renderable->getProperties()['multiple'] ?? false;
×
71
        }
72

73
        $result = $this->viewHelperInvoker->invoke(
×
74
            $renderingContext,
×
75
            Form\ViewHelpers\Form\UploadedResourceViewHelper::class,
×
NEW
76
            $arguments,
×
77
            static function () use ($renderingContext, &$resource, $resourceVariableName) {
×
78
                $resource = $renderingContext->getVariableProvider()->get($resourceVariableName);
×
79
            },
×
80
        );
×
81
        $inputViewModel = new Domain\ViewModel\ViewHelperContainedViewModel($renderable, $result);
×
82

NEW
83
        if (!$this->isValidResource($resource)) {
×
84
            return $inputViewModel;
×
85
        }
86

NEW
87
        $uploads = [];
×
88
        $viewModels = [
×
89
            'uploadField' => $inputViewModel,
×
NEW
90
            'resourcePointerFields' => $this->buildResourcePointerFields(
×
NEW
91
                $renderable,
×
NEW
92
                $result->extractChildNodes('input[@type="hidden"]'),
×
NEW
93
            ),
×
UNCOV
94
        ];
×
95

NEW
96
        if (!is_iterable($resource)) {
×
NEW
97
            $resource = [$resource];
×
98
        }
99

NEW
100
        $fileIndex = 0;
×
NEW
101
        foreach ($resource as $fileReference) {
×
102
            // @todo Remove first condition once support for TYPO3 v13 is dropped
NEW
103
            if ($this->typo3Version->getMajorVersion() >= 14 && (bool)($renderable->getProperties()['allowRemoval'] ?? false)) {
×
NEW
104
                $deleteCheckbox = $this->buildDeleteCheckbox($renderable, $renderingContext, $fileReference, $fileIndex++);
×
105
            } else {
NEW
106
                $deleteCheckbox = null;
×
107
            }
108

NEW
109
            $uploads[] = new Domain\ViewModel\FileResourceViewModel($renderable, $fileReference, $deleteCheckbox);
×
110
        }
111

NEW
112
        $viewModels['uploads'] = new Domain\ViewModel\ViewModelCollection($renderable, $uploads);
×
113

UNCOV
114
        return new Domain\ViewModel\ViewModelCollection($renderable, $viewModels);
×
115
    }
116

117
    /**
118
     * @param list<FluidStandalone\Core\ViewHelper\TagBuilder> $hiddenFields
119
     */
NEW
120
    private function buildResourcePointerFields(
×
121
        Form\Domain\Model\FormElements\FileUpload $renderable,
122
        array $hiddenFields,
123
    ): Domain\ViewModel\ViewModelCollection {
NEW
124
        $resourcePointerFields = [];
×
125

NEW
126
        foreach ($hiddenFields as $hiddenField) {
×
NEW
127
            $resourcePointerFields[] = new Domain\ViewModel\StandaloneTagViewModel($renderable, $hiddenField);
×
128
        }
129

NEW
130
        return new Domain\ViewModel\ViewModelCollection($renderable, $resourcePointerFields);
×
131
    }
132

NEW
133
    private function buildDeleteCheckbox(
×
134
        Form\Domain\Model\FormElements\FileUpload $renderable,
135
        Fluid\Core\Rendering\RenderingContext $renderingContext,
136
        Extbase\Domain\Model\FileReference $fileReference,
137
        int $fileIndex
138
    ): Domain\ViewModel\FormFieldViewModel {
NEW
139
        $result = $this->viewHelperInvoker->invoke(
×
NEW
140
            $renderingContext,
×
NEW
141
            Form\ViewHelpers\Form\UploadDeleteCheckboxViewHelper::class,
×
NEW
142
            [
×
NEW
143
                'property' => $renderable->getIdentifier(),
×
NEW
144
                'fileReference' => $fileReference,
×
NEW
145
                'fileIndex' => $fileIndex,
×
NEW
146
            ],
×
NEW
147
        );
×
148

NEW
149
        return Domain\ViewModel\FormFieldViewModel::forLabelAndElement(
×
NEW
150
            $fileReference->getOriginalResource()->getOriginalFile()->getName(),
×
NEW
151
            new Domain\ViewModel\ViewHelperContainedViewModel($renderable, $result),
×
NEW
152
        );
×
153
    }
154

155
    /**
156
     * @phpstan-assert-if-true Extbase\Domain\Model\FileReference|Extbase\Persistence\ObjectStorage<Extbase\Domain\Model\FileReference> $resource
157
     */
NEW
158
    private function isValidResource(mixed $resource): bool
×
159
    {
NEW
160
        if ($resource instanceof Extbase\Domain\Model\FileReference) {
×
NEW
161
            return true;
×
162
        }
163

164
        // @todo Combine with previous condition once support for TYPO3 v13 is dropped
NEW
165
        if ($this->typo3Version->getMajorVersion() >= 14
×
NEW
166
            && $resource instanceof Extbase\Persistence\ObjectStorage
×
NEW
167
            && count($resource) > 0
×
168
        ) {
NEW
169
            return true;
×
170
        }
171

NEW
172
        return false;
×
173
    }
174
}
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