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

eliashaeussler / typo3-form-consent / 11109919324

30 Sep 2024 04:06PM UTC coverage: 94.261% (+0.02%) from 94.24%
11109919324

Pull #319

github

web-flow
Merge 9e8082d7a into 669092931
Pull Request #319: Respect order of template/partial/layout root paths

8 of 8 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

772 of 819 relevant lines covered (94.26%)

14.55 hits per line

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

99.33
/Classes/Domain/Finishers/FinisherOptions.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "form_consent".
7
 *
8
 * Copyright (C) 2021-2024 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\Typo3FormConsent\Domain\Finishers;
25

26
use ArrayAccess;
27
use EliasHaeussler\Typo3FormConsent\Configuration;
28
use EliasHaeussler\Typo3FormConsent\Exception;
29
use EliasHaeussler\Typo3FormConsent\Extension;
30
use TYPO3\CMS\Core;
31
use TYPO3\CMS\Extbase;
32
use TYPO3\CMS\Fluid;
33
use TYPO3\CMS\Form;
34

35
/**
36
 * FinisherOptions
37
 *
38
 * @author Elias Häußler <elias@haeussler.dev>
39
 * @license GPL-2.0-or-later
40
 *
41
 * @implements ArrayAccess<string, string|int|bool|Fluid\View\TemplatePaths>
42
 */
43
final class FinisherOptions implements \ArrayAccess
44
{
45
    private static ?Core\Domain\Repository\PageRepository $pageRepository = null;
46

47
    /**
48
     * @var callable(string): mixed
49
     */
50
    private $optionFetcher;
51

52
    /**
53
     * @var array{
54
     *     subject?: string,
55
     *     templatePaths?: Fluid\View\TemplatePaths,
56
     *     recipientAddress?: string,
57
     *     recipientName?: string,
58
     *     senderAddress?: string,
59
     *     senderName?: string,
60
     *     replyToAddress?: string,
61
     *     replyToName?: string,
62
     *     approvalPeriod?: int,
63
     *     confirmationPid?: int,
64
     *     storagePid?: int,
65
     *     showDismissLink?: bool,
66
     *     requireApproveVerification?: bool,
67
     *     requireDismissVerification?: bool,
68
     * }
69
     */
70
    private array $parsedOptions = [];
71

72
    /**
73
     * @param callable(string): mixed $optionFetcher
74
     */
75
    public function __construct(callable $optionFetcher)
58✔
76
    {
77
        $this->optionFetcher = $optionFetcher;
58✔
78
    }
79

80
    public function getSubject(): string
27✔
81
    {
82
        if (isset($this->parsedOptions['subject'])) {
27✔
83
            return $this->parsedOptions['subject'];
1✔
84
        }
85

86
        $subject = trim((string)($this->optionFetcher)('subject'));
27✔
87

88
        if (str_starts_with($subject, 'LLL:')) {
27✔
89
            $subject = Configuration\Localization::translate($subject);
1✔
90
        }
91
        if ($subject === '') {
27✔
92
            $subject = Configuration\Localization::forKey('consentMail.subject', null, true);
25✔
93
        }
94

95
        return $this->parsedOptions['subject'] = $subject;
27✔
96
    }
97

98
    public function getTemplatePaths(): Fluid\View\TemplatePaths
25✔
99
    {
100
        if (isset($this->parsedOptions['templatePaths'])) {
25✔
101
            return $this->parsedOptions['templatePaths'];
1✔
102
        }
103

104
        $configurationManager = Core\Utility\GeneralUtility::makeInstance(Extbase\Configuration\ConfigurationManagerInterface::class);
25✔
105
        $typoScriptConfiguration = $configurationManager->getConfiguration(
25✔
106
            Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
25✔
107
            Extension::NAME
25✔
108
        );
25✔
109
        $typoScriptTemplateConfiguration = $typoScriptConfiguration['view'] ?? [];
25✔
110

111
        $defaultTemplateConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL'];
25✔
112
        $finisherTemplateConfiguration = [
25✔
113
            'templateRootPaths' => ($this->optionFetcher)('templateRootPaths') ?? [],
25✔
114
            'partialRootPaths' => ($this->optionFetcher)('partialRootPaths') ?? [],
25✔
115
            'layoutRootPaths' => ($this->optionFetcher)('layoutRootPaths') ?? [],
25✔
116
        ];
25✔
117

118
        $mergedTemplateConfiguration = array_replace_recursive(
25✔
119
            $defaultTemplateConfiguration,
25✔
120
            $typoScriptTemplateConfiguration,
25✔
121
            $finisherTemplateConfiguration
25✔
122
        );
25✔
123

124
        ksort($mergedTemplateConfiguration['templateRootPaths']);
25✔
125
        ksort($mergedTemplateConfiguration['partialRootPaths']);
25✔
126
        ksort($mergedTemplateConfiguration['layoutRootPaths']);
25✔
127

128
        return $this->parsedOptions['templatePaths'] = Core\Utility\GeneralUtility::makeInstance(
25✔
129
            Fluid\View\TemplatePaths::class,
25✔
130
            $mergedTemplateConfiguration
25✔
131
        );
25✔
132
    }
133

134
    public function getRecipientAddress(): string
29✔
135
    {
136
        if (isset($this->parsedOptions['recipientAddress'])) {
29✔
137
            return $this->parsedOptions['recipientAddress'];
25✔
138
        }
139

140
        $recipientAddress = ($this->optionFetcher)('recipientAddress');
29✔
141

142
        if (!\is_string($recipientAddress)) {
29✔
143
            $this->throwException('recipientAddress.invalid', 1640186663);
1✔
144
        }
145
        if (trim($recipientAddress) === '') {
28✔
146
            $this->throwException('recipientAddress.empty', 1576947638);
2✔
147
        }
148
        if (!Core\Utility\GeneralUtility::validEmail($recipientAddress)) {
26✔
149
            $this->throwException('recipientAddress.invalid', 1576947682);
1✔
150
        }
151

152
        return $this->parsedOptions['recipientAddress'] = $recipientAddress;
25✔
153
    }
154

155
    public function getRecipientName(): string
25✔
156
    {
157
        return $this->parsedOptions['recipientName']
25✔
158
            ?? $this->parsedOptions['recipientName'] = (string)($this->optionFetcher)('recipientName');
25✔
159
    }
160

161
    public function getSenderAddress(): string
27✔
162
    {
163
        if (isset($this->parsedOptions['senderAddress'])) {
27✔
164
            return $this->parsedOptions['senderAddress'];
1✔
165
        }
166

167
        $senderAddress = ($this->optionFetcher)('senderAddress');
27✔
168

169
        if (!\is_string($senderAddress)) {
27✔
170
            $this->throwException('senderAddress.invalid', 1640186811);
1✔
171
        }
172
        if (trim($senderAddress) !== '' && !Core\Utility\GeneralUtility::validEmail($senderAddress)) {
26✔
173
            $this->throwException('senderAddress.invalid', 1587842752);
1✔
174
        }
175

176
        return $this->parsedOptions['senderAddress'] = $senderAddress;
25✔
177
    }
178

179
    public function getSenderName(): string
2✔
180
    {
181
        return $this->parsedOptions['senderName']
2✔
182
            ?? $this->parsedOptions['senderName'] = (string)($this->optionFetcher)('senderName');
2✔
183
    }
184

185
    public function getReplyToAddress(): string
27✔
186
    {
187
        if (isset($this->parsedOptions['replyToAddress'])) {
27✔
188
            return $this->parsedOptions['replyToAddress'];
1✔
189
        }
190

191
        $replyToAddress = ($this->optionFetcher)('replyToAddress');
27✔
192

193
        if (!\is_string($replyToAddress)) {
27✔
194
            $this->throwException('replyToAddress.invalid', 1716797809);
1✔
195
        }
196
        if (trim($replyToAddress) !== '' && !Core\Utility\GeneralUtility::validEmail($replyToAddress)) {
26✔
197
            $this->throwException('replyToAddress.invalid', 1716797811);
1✔
198
        }
199

200
        return $this->parsedOptions['replyToAddress'] = $replyToAddress;
25✔
201
    }
202

203
    public function getReplyToName(): string
2✔
204
    {
205
        return $this->parsedOptions['replyToName']
2✔
206
            ?? $this->parsedOptions['replyToName'] = (string)($this->optionFetcher)('replyToName');
2✔
207
    }
208

209
    public function getApprovalPeriod(): int
28✔
210
    {
211
        if (isset($this->parsedOptions['approvalPeriod'])) {
28✔
212
            return $this->parsedOptions['approvalPeriod'];
1✔
213
        }
214

215
        $approvalPeriod = (int)($this->optionFetcher)('approvalPeriod');
28✔
216

217
        if ($approvalPeriod < 0) {
28✔
218
            $this->throwException('approvalPeriod.invalid', 1576948900);
1✔
219
        }
220

221
        return $this->parsedOptions['approvalPeriod'] = $approvalPeriod;
27✔
222
    }
223

224
    public function getConfirmationPid(): int
27✔
225
    {
226
        if (isset($this->parsedOptions['confirmationPid'])) {
27✔
227
            return $this->parsedOptions['confirmationPid'];
1✔
228
        }
229

230
        $confirmationPid = (int)($this->optionFetcher)('confirmationPid');
27✔
231

232
        if ($confirmationPid <= 0) {
27✔
233
            $this->throwException('confirmationPid.empty', 1576948961);
1✔
234
        }
235
        if (!\is_array($this->getPageRepository()->checkRecord('pages', $confirmationPid))) {
26✔
236
            $this->throwException('confirmationPid.invalid', 1576949163);
1✔
237
        }
238

239
        return $this->parsedOptions['confirmationPid'] = $confirmationPid;
25✔
240
    }
241

242
    public function getStoragePid(): int
29✔
243
    {
244
        if (isset($this->parsedOptions['storagePid'])) {
29✔
245
            return $this->parsedOptions['storagePid'];
1✔
246
        }
247

248
        $storagePid = (int)($this->optionFetcher)('storagePid');
29✔
249

250
        // Use default storage pid if storage pid is not defined in form
251
        if ($storagePid === 0) {
29✔
252
            $storagePid = $this->fetchDefaultStoragePid();
26✔
253
        }
254

255
        // Early return if storage pid is not set since it is not a mandatory option
256
        if ($storagePid === 0) {
29✔
257
            return $this->parsedOptions['storagePid'] = $storagePid;
25✔
258
        }
259

260
        if ($storagePid < 0) {
4✔
261
            $this->throwException('storagePid.empty', 1576951495);
1✔
262
        }
263
        if (!\is_array($this->getPageRepository()->checkRecord('pages', $storagePid))) {
3✔
264
            $this->throwException('storagePid.invalid', 1576951499);
1✔
265
        }
266

267
        return $this->parsedOptions['storagePid'] = $storagePid;
2✔
268
    }
269

270
    public function getShowDismissLink(): bool
25✔
271
    {
272
        return $this->parsedOptions['showDismissLink']
25✔
273
            ?? $this->parsedOptions['showDismissLink'] = (bool)($this->optionFetcher)('showDismissLink');
25✔
274
    }
275

276
    public function requiresVerificationForApproval(): bool
25✔
277
    {
278
        return $this->parsedOptions['requireApproveVerification']
25✔
279
            ?? $this->parsedOptions['requireApproveVerification'] = (bool)($this->optionFetcher)('requireApproveVerification');
25✔
280
    }
281

282
    public function requiresVerificationForDismissal(): bool
25✔
283
    {
284
        return $this->parsedOptions['requireDismissVerification']
25✔
285
            ?? $this->parsedOptions['requireDismissVerification'] = (bool)($this->optionFetcher)('requireDismissVerification');
25✔
286
    }
287

288
    public function offsetExists($offset): bool
1✔
289
    {
290
        if (!\is_string($offset)) {
1✔
UNCOV
291
            return false;
×
292
        }
293

294
        $getterMethodName = 'get' . ucfirst($offset);
1✔
295
        if (method_exists($this, $getterMethodName)) {
1✔
296
            return true;
1✔
297
        }
298

299
        return false;
1✔
300
    }
301

302
    public function offsetGet($offset): mixed
1✔
303
    {
304
        if (!\is_string($offset)) {
1✔
305
            return null;
1✔
306
        }
307

308
        $getterMethodName = 'get' . ucfirst($offset);
1✔
309
        $callable = [$this, $getterMethodName];
1✔
310

311
        if (\is_callable($callable)) {
1✔
312
            return \call_user_func($callable);
1✔
313
        }
314

315
        return null;
1✔
316
    }
317

318
    public function offsetSet($offset, $value): void
1✔
319
    {
320
        throw Exception\NotAllowedException::forMethod(__METHOD__);
1✔
321
    }
322

323
    public function offsetUnset($offset): void
1✔
324
    {
325
        throw Exception\NotAllowedException::forMethod(__METHOD__);
1✔
326
    }
327

328
    private function fetchDefaultStoragePid(): int
26✔
329
    {
330
        $configurationManager = Core\Utility\GeneralUtility::makeInstance(Extbase\Configuration\ConfigurationManagerInterface::class);
26✔
331
        $configuration = $configurationManager->getConfiguration(
26✔
332
            Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
26✔
333
            Extension::NAME,
26✔
334
            Extension::PLUGIN,
26✔
335
        );
26✔
336

337
        return (int)($configuration['persistence']['storagePid'] ?? 0);
26✔
338
    }
339

340
    private function getPageRepository(): Core\Domain\Repository\PageRepository
29✔
341
    {
342
        if (self::$pageRepository === null) {
29✔
343
            self::$pageRepository = Core\Utility\GeneralUtility::makeInstance(Core\Domain\Repository\PageRepository::class);
25✔
344
        }
345

346
        return self::$pageRepository;
29✔
347
    }
348

349
    /**
350
     * @throws Form\Domain\Finishers\Exception\FinisherException
351
     */
352
    private function throwException(string $message, int $code = 0): never
13✔
353
    {
354
        throw new Form\Domain\Finishers\Exception\FinisherException(
13✔
355
            Configuration\Localization::forFormValidation($message, true),
13✔
356
            $code,
13✔
357
        );
13✔
358
    }
359
}
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

© 2025 Coveralls, Inc