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

CPS-IT / handlebars-forms / 24495333522

16 Apr 2026 06:18AM UTC coverage: 0.562% (-0.003%) from 0.565%
24495333522

push

github

eliashaeussler
[BUGFIX] Disable cache on form submit

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

7 of 1246 relevant lines covered (0.56%)

0.02 hits per line

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

0.0
/Classes/Domain/Renderer/HandlebarsFormRenderer.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\Renderer;
19

20
use CPSIT\Typo3Handlebars\View;
21
use Symfony\Component\DependencyInjection;
22
use TYPO3\CMS\Core;
23
use TYPO3\CMS\Extbase;
24
use TYPO3\CMS\Form;
25
use TYPO3\CMS\Frontend;
26

27
/**
28
 * HandlebarsFormRenderer
29
 *
30
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
31
 * @license GPL-2.0-or-later
32
 */
33
#[DependencyInjection\Attribute\Autoconfigure(public: true, shared: false)]
34
final class HandlebarsFormRenderer extends Form\Domain\Renderer\AbstractElementRenderer
35
{
36
    private readonly Core\Information\Typo3Version $typo3Version;
37

38
    public function __construct(
×
39
        private readonly Extbase\Configuration\ConfigurationManagerInterface $configurationManager,
40
        private readonly View\HandlebarsViewFactory $viewFactory,
41
        private readonly Core\TypoScript\TypoScriptService $typoScriptService,
42
    ) {
43
        $this->typo3Version = new Core\Information\Typo3Version();
×
44
    }
45

46
    public function render(): string
×
47
    {
NEW
48
        $this->disableCacheOnSubmit();
×
49

50
        $view = $this->resolveViewFromConfiguration() ?? $this->resolveDefaultView();
×
51
        $view->assign('form', $this->formRuntime);
×
52

53
        match ($this->typo3Version->getMajorVersion()) {
×
54
            13 => $this->triggerBeforeRenderingHook(),
×
55
            14 => $this->triggerBeforeRenderableIsRenderedEvent(),
×
56
            default => null,
×
57
        };
×
58

59
        if ($view instanceof View\HandlebarsView) {
×
60
            $templateName = $view->getTemplateName() ?? $this->formRuntime->getTemplateName();
×
61
        } else {
62
            $templateName = $this->formRuntime->getTemplateName();
×
63
        }
64

65
        return $view->render($templateName);
×
66
    }
67

68
    private function resolveViewFromConfiguration(): ?View\HandlebarsView
×
69
    {
70
        $request = $this->formRuntime->getRequest();
×
71
        $contentObjectRenderer = $request->getAttribute('currentContentObject');
×
72

73
        // Early return when outside of content object rendering
74
        if (!($contentObjectRenderer instanceof Frontend\ContentObject\ContentObjectRenderer)) {
×
75
            return null;
×
76
        }
77

78
        // Resolve form configuration from plugin configuration
79
        $pluginConfiguration = $this->configurationManager->getConfiguration(
×
80
            Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
×
81
        );
×
82
        $formConfiguration = $pluginConfiguration['handlebarsForms'] ?? null;
×
83

84
        // Early return if no handlebars configuration is available
85
        if (!is_array($formConfiguration)) {
×
86
            return null;
×
87
        }
88

89
        // HANDLEBARSTEMPLATE content object requires TypoScript configuration, so let's convert early
90
        $typoScriptConfiguration = $this->typoScriptService->convertPlainArrayToTypoScriptArray($formConfiguration);
×
91

92
        // Resolve TypoScript configuration based on form identifier
93
        $resolvedConfiguration = [];
×
94
        $possibleConfigurationKeys = [
×
95
            // Fallback
96
            'default',
×
97
            // Unique form identifier
98
            $this->formRuntime->getIdentifier(),
×
99
            // Original form identifier
100
            $this->formRuntime->getRenderingOptions()['_originalIdentifier'],
×
101
            // Form persistence identifier
102
            $this->formRuntime->getFormDefinition()->getPersistenceIdentifier(),
×
103
        ];
×
104
        foreach ($possibleConfigurationKeys as $possibleConfigurationKey) {
×
105
            if (is_string($possibleConfigurationKey) &&
×
106
                is_array($typoScriptConfiguration[$possibleConfigurationKey . '.'] ?? null)
×
107
            ) {
108
                Core\Utility\ArrayUtility::mergeRecursiveWithOverrule(
×
109
                    $resolvedConfiguration,
×
110
                    $typoScriptConfiguration[$possibleConfigurationKey . '.'],
×
111
                );
×
112
            }
113
        }
114

115
        return new View\HandlebarsView(
×
116
            $contentObjectRenderer,
×
117
            $this->typoScriptService,
×
118
            $resolvedConfiguration,
×
119
            $request,
×
120
        );
×
121
    }
122

123
    private function resolveDefaultView(): Core\View\ViewInterface
×
124
    {
125
        $renderingOptions = $this->formRuntime->getRenderingOptions();
×
126
        $templateRootPaths = $renderingOptions['templateRootPaths'] ?? [];
×
127
        $partialRootPaths = $renderingOptions['partialRootPaths'] ?? [];
×
128
        $layoutRootPaths = $renderingOptions['layoutRootPaths'] ?? [];
×
129

130
        if (!is_array($templateRootPaths)) {
×
131
            $templateRootPaths = null;
×
132
        }
133
        if (!is_array($partialRootPaths)) {
×
134
            $partialRootPaths = null;
×
135
        }
136
        if (!is_array($layoutRootPaths)) {
×
137
            $layoutRootPaths = null;
×
138
        }
139

140
        $viewFactoryData = new Core\View\ViewFactoryData(
×
141
            templateRootPaths: $templateRootPaths,
×
142
            partialRootPaths: $partialRootPaths,
×
143
            layoutRootPaths: $layoutRootPaths,
×
144
            request: $this->formRuntime->getRequest(),
×
145
        );
×
146

147
        return $this->viewFactory->create($viewFactoryData);
×
148
    }
149

NEW
150
    private function disableCacheOnSubmit(): void
×
151
    {
NEW
152
        $request = $this->formRuntime->getRequest();
×
NEW
153
        $cacheInstruction = $request->getAttribute('frontend.cache.instruction');
×
154

NEW
155
        if ($cacheInstruction instanceof Frontend\Cache\CacheInstruction && $request->getMethod() === 'POST') {
×
NEW
156
            $cacheInstruction->disableCache('EXT:handlebars_forms: Rendering of submitted forms must not be cached.');
×
157
        }
158
    }
159

160
    /**
161
     * @todo Remove once support for TYPO3 v13 is dropped
162
     */
163
    private function triggerBeforeRenderingHook(): void
×
164
    {
165
        /** @var class-string $className */
166
        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeRendering'] ?? [] as $className) {
×
167
            $hookObj = Core\Utility\GeneralUtility::makeInstance($className);
×
168

169
            if (method_exists($hookObj, 'beforeRendering')) {
×
170
                $hookObj->beforeRendering($this->formRuntime, $this->formRuntime->getFormDefinition());
×
171
            }
172
        }
173
    }
174

175
    /**
176
     * @todo Enable once support for TYPO3 v14 is added
177
     */
178
    private function triggerBeforeRenderableIsRenderedEvent(): void
×
179
    {
180
        // $this->eventDispatcher->dispatch(
181
        //     new Form\Event\BeforeRenderableIsRenderedEvent($this->formRuntime->getFormDefinition(), $this->formRuntime),
182
        // );
183
    }
×
184
}
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