ExtendedTemplateService::ext_getObjTree()   F
last analyzed

Complexity

Conditions 31
Paths > 20000

Size

Total Lines 103
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 68
c 0
b 0
f 0
dl 0
loc 103
rs 0
cc 31
nc 537680
nop 6

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Core\TypoScript;
17
18
use TYPO3\CMS\Backend\Routing\UriBuilder;
19
use TYPO3\CMS\Backend\Utility\BackendUtility;
20
use TYPO3\CMS\Core\Context\Context;
21
use TYPO3\CMS\Core\Database\ConnectionPool;
22
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
23
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
24
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
25
use TYPO3\CMS\Core\Exception;
26
use TYPO3\CMS\Core\Imaging\Icon;
27
use TYPO3\CMS\Core\Imaging\IconFactory;
28
use TYPO3\CMS\Core\Localization\LanguageService;
29
use TYPO3\CMS\Core\TypoScript\Parser\ConstantConfigurationParser;
30
use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
31
use TYPO3\CMS\Core\Utility\ArrayUtility;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
use TYPO3\CMS\Core\Utility\MathUtility;
34
use TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
35
36
/**
37
 * TSParser extension class to TemplateService
38
 * Contains functions for the TS module in TYPO3 backend
39
 *
40
 * @internal this is only used for the TYPO3 TypoScript Template module, which should not be used in Extensions
41
 */
42
class ExtendedTemplateService extends TemplateService
43
{
44
    /**
45
     * @var array
46
     */
47
    protected $categories = [
48
        'basic' => [],
49
        // Constants of superior importance for the template-layout. This is dimensions, imagefiles and enabling of various features. The most basic constants, which you would almost always want to configure.
50
        'menu' => [],
51
        // Menu setup. This includes fontfiles, sizes, background images. Depending on the menutype.
52
        'content' => [],
53
        // All constants related to the display of pagecontent elements
54
        'page' => [],
55
        // General configuration like metatags, link targets
56
        'advanced' => [],
57
        // Advanced functions, which are used very seldom.
58
        'all' => []
59
    ];
60
61
    /**
62
     * Tsconstanteditor
63
     *
64
     * @var int
65
     */
66
    public $ext_inBrace = 0;
67
68
    /**
69
     * Tsbrowser
70
     *
71
     * @var array
72
     */
73
    public $tsbrowser_searchKeys = [];
74
75
    /**
76
     * @var array
77
     */
78
    public $tsbrowser_depthKeys = [];
79
80
    /**
81
     * @var string
82
     */
83
    public $constantMode = '';
84
85
    /**
86
     * @var string
87
     */
88
    public $regexMode = '';
89
90
    /**
91
     * @var int
92
     */
93
    public $ext_expandAllNotes = 0;
94
95
    /**
96
     * @var int
97
     */
98
    public $ext_noPMicons = 0;
99
100
    /**
101
     * Ts analyzer
102
     *
103
     * @var array
104
     */
105
    public $templateTitles = [];
106
107
    /**
108
     * @var array|null
109
     */
110
    protected $lnToScript;
111
112
    /**
113
     * @var array
114
     */
115
    public $clearList_const_temp;
116
117
    /**
118
     * @var array
119
     */
120
    public $clearList_setup_temp;
121
122
    /**
123
     * @var string
124
     */
125
    public $bType = '';
126
127
    /**
128
     * @var bool
129
     */
130
    public $linkObjects = false;
131
132
    /**
133
     * @var bool
134
     */
135
    public $changed = false;
136
137
    /**
138
     * @var int[]
139
     */
140
    protected $objReg = [];
141
142
    /**
143
     * @var array
144
     */
145
    public $raw = [];
146
147
    /**
148
     * @var int
149
     */
150
    public $rawP = 0;
151
152
    /**
153
     * @var string
154
     */
155
    public $lastComment = '';
156
157
    /**
158
     * @var array
159
     */
160
    protected $inlineJavaScript = [];
161
    /**
162
     * @var \TYPO3\CMS\Core\TypoScript\Parser\ConstantConfigurationParser
163
     */
164
    private $constantParser;
165
166
    /**
167
     * @param Context|null $context
168
     * @param \TYPO3\CMS\Core\TypoScript\Parser\ConstantConfigurationParser $constantParser
169
     */
170
    public function __construct(Context $context = null, ConstantConfigurationParser $constantParser = null)
171
    {
172
        parent::__construct($context);
173
        $this->constantParser = $constantParser ?? GeneralUtility::makeInstance(ConstantConfigurationParser::class);
174
        // Disabled in backend context
175
        $this->tt_track = false;
176
        $this->verbose = false;
177
    }
178
179
    /**
180
     * Gets the inline JavaScript.
181
     *
182
     * @return array
183
     */
184
    public function getInlineJavaScript()
185
    {
186
        return $this->inlineJavaScript;
187
    }
188
189
    /**
190
     * Substitute constant
191
     *
192
     * @param string $all
193
     * @return string
194
     */
195
    public function substituteConstants($all)
196
    {
197
        return preg_replace_callback('/\\{\\$(.[^}]+)\\}/', [$this, 'substituteConstantsCallBack'], $all);
198
    }
199
200
    /**
201
     * Call back method for preg_replace_callback in substituteConstants
202
     *
203
     * @param array $matches Regular expression matches
204
     * @return string Replacement
205
     * @see substituteConstants()
206
     */
207
    public function substituteConstantsCallBack($matches)
208
    {
209
        $marker = substr(md5($matches[0]), 0, 6);
210
        switch ($this->constantMode) {
211
            case 'const':
212
                $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? '##' . $marker . '_B##' . $this->flatSetup[$matches[1]] . '##' . $marker . '_M##' . $matches[0] . '##' . $marker . '_E##' : $matches[0];
213
                break;
214
            case 'subst':
215
                $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? '##' . $marker . '_B##' . $matches[0] . '##' . $marker . '_M##' . $this->flatSetup[$matches[1]] . '##' . $marker . '_E##' : $matches[0];
216
                break;
217
            case 'untouched':
218
                $ret_val = $matches[0];
219
                break;
220
            default:
221
                $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
222
        }
223
        return $ret_val;
224
    }
225
226
    /**
227
     * Substitute markers added in substituteConstantsCallBack()
228
     * with ##6chars_B##value1##6chars_M##value2##6chars_E##
229
     *
230
     * @param string $all
231
     * @return string
232
     */
233
    public function substituteCMarkers($all)
234
    {
235
        switch ($this->constantMode) {
236
            case 'const':
237
            case 'subst':
238
                $all = preg_replace(
239
                    '/##[a-z0-9]{6}_B##(.*?)##[a-z0-9]{6}_M##(.*?)##[a-z0-9]{6}_E##/',
240
                    '<strong class="text-success" data-bs-toggle="tooltip" data-bs-placement="top" data-title="$1" title="$1">$2</strong>',
241
                    $all
242
                );
243
                break;
244
            default:
245
        }
246
        return $all;
247
    }
248
249
    /**
250
     * Parse constants with respect to the constant-editor in this module.
251
     * In particular comments in the code are registered and the edit_divider is taken into account.
252
     *
253
     * @return array
254
     */
255
    public function generateConfig_constants()
256
    {
257
        // Parse constants
258
        $constants = GeneralUtility::makeInstance(TypoScriptParser::class);
259
        // Register comments!
260
        $constants->regComments = true;
261
        /** @var ConditionMatcher $matchObj */
262
        $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
263
        // Matches ALL conditions in TypoScript
264
        $matchObj->setSimulateMatchResult(true);
265
        $c = 0;
266
        $cc = count($this->constants);
267
        $defaultConstants = [];
268
        foreach ($this->constants as $str) {
269
            $c++;
270
            if ($c == $cc) {
271
                $defaultConstants = ArrayUtility::flatten($constants->setup, '', true);
272
            }
273
            $constants->parse($str, $matchObj);
274
        }
275
        $this->setup['constants'] = $constants->setup;
276
        $flatSetup = ArrayUtility::flatten($constants->setup, '', true);
277
        return $this->constantParser->parseComments(
278
            $flatSetup,
279
            $defaultConstants
280
        );
281
    }
282
283
    /**
284
     * @param array $theSetup
285
     * @param string $theKey
286
     * @return array
287
     */
288
    public function ext_getSetup($theSetup, $theKey)
289
    {
290
        $parts = explode('.', $theKey, 2);
291
        if ((string)$parts[0] !== '' && is_array($theSetup[$parts[0] . '.'] ?? false)) {
292
            if (trim($parts[1]) !== '') {
293
                return $this->ext_getSetup($theSetup[$parts[0] . '.'], trim($parts[1]));
294
            }
295
            return [$theSetup[$parts[0] . '.'], $theSetup[$parts[0]]];
296
        }
297
        if (trim($theKey) !== '') {
298
            return [[], $theSetup[$theKey]];
299
        }
300
        return [$theSetup, ''];
301
    }
302
303
    /**
304
     * Get object tree
305
     *
306
     * @param array $arr
307
     * @param string $depth_in
308
     * @param string $depthData
309
     * @param string $parentType (unused)
310
     * @param string $parentValue (unused)
311
     * @param string $alphaSort sorts the array keys / tree by alphabet when set to 1
312
     * @return string
313
     */
314
    public function ext_getObjTree($arr, $depth_in, $depthData, $parentType = '', $parentValue = '', $alphaSort = '0')
315
    {
316
        $HTML = '';
317
        if ($alphaSort == '1') {
318
            ksort($arr);
319
        }
320
        $keyArr_num = [];
321
        $keyArr_alpha = [];
322
        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
323
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
324
        foreach ($arr as $key => $value) {
325
            // Don't do anything with comments / linenumber registrations...
326
            if (substr($key, -2) !== '..') {
327
                $key = preg_replace('/\\.$/', '', $key) ?? '';
328
                if (substr($key, -1) !== '.') {
329
                    if (MathUtility::canBeInterpretedAsInteger($key)) {
330
                        $keyArr_num[$key] = $arr[$key] ?? '';
331
                    } else {
332
                        $keyArr_alpha[$key] = $arr[$key] ?? '';
333
                    }
334
                }
335
            }
336
        }
337
        ksort($keyArr_num);
338
        $keyArr = $keyArr_num + $keyArr_alpha;
339
        if ($depth_in) {
340
            $depth_in = $depth_in . '.';
341
        }
342
        foreach ($keyArr as $key => $value) {
343
            $depth = $depth_in . $key;
344
            // This excludes all constants starting with '_' from being shown.
345
            if ($this->bType !== 'const' || $depth[0] !== '_') {
346
                $goto = substr(md5($depth), 0, 6);
347
                $deeper = is_array($arr[$key . '.'] ?? null) && (($this->tsbrowser_depthKeys[$depth] ?? false) || $this->ext_expandAllNotes);
348
                $PM = is_array($arr[$key . '.'] ?? null) && !$this->ext_noPMicons ? ($deeper ? 'minus' : 'plus') : 'join';
349
                $HTML .= $depthData . '<li><span class="list-tree-group">';
350
                if ($PM !== 'join') {
351
                    $urlParameters = [
352
                        'id' => (int)GeneralUtility::_GP('id'),
353
                        'tsbr[' . $depth . ']' => $deeper ? 0 : 1
354
                    ];
355
                    $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters) . '#' . $goto;
356
                    $HTML .= '<a class="list-tree-control' . ($PM === 'minus' ? ' list-tree-control-open' : ' list-tree-control-closed') . '" name="' . $goto . '" href="' . htmlspecialchars($aHref) . '"><i class="fa"></i></a>';
357
                }
358
                $label = $key;
359
                // Read only...
360
                if (($depth === 'types') && $this->bType === 'setup') {
361
                    $label = '<span style="color: #666666;">' . $label . '</span>';
362
                } else {
363
                    if ($this->linkObjects) {
364
                        $urlParameters = [
365
                            'id' => (int)GeneralUtility::_GP('id'),
366
                            'sObj' => $depth
367
                        ];
368
                        $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
369
                        if ($this->bType !== 'const') {
370
                            $ln = is_array($arr[$key . '.ln..'] ?? null) ? 'Defined in: ' . $this->lineNumberToScript($arr[$key . '.ln..']) : 'N/A';
371
                        } else {
372
                            $ln = '';
373
                        }
374
                        if (($this->tsbrowser_searchKeys[$depth] ?? 0) & 4) {
375
                            // The key has matched the search string
376
                            $label = '<strong class="text-danger">' . $label . '</strong>';
377
                        }
378
                        $label = '<a href="' . htmlspecialchars($aHref) . '" title="' . htmlspecialchars($depth_in . $key . ' ' . $ln) . '">' . $label . '</a>';
379
                    }
380
                }
381
                $HTML .= '<span class="list-tree-label" title="' . htmlspecialchars($depth_in . $key) . '">[' . $label . ']</span>';
382
                if (isset($arr[$key])) {
383
                    $theValue = $arr[$key];
384
                    // The value has matched the search string
385
                    if (($this->tsbrowser_searchKeys[$depth] ?? 0) & 2) {
386
                        $HTML .= ' = <span class="list-tree-value text-danger">' . htmlspecialchars($theValue) . '</span>';
387
                    } else {
388
                        $HTML .= ' = <span class="list-tree-value">' . htmlspecialchars($theValue) . '</span>';
389
                    }
390
                    if ($this->ext_regComments && isset($arr[$key . '..'])) {
391
                        $comment = (string)$arr[$key . '..'];
392
                        // Skip INCLUDE_TYPOSCRIPT comments, they are almost useless
393
                        if (!preg_match('/### <INCLUDE_TYPOSCRIPT:.*/', $comment)) {
394
                            // Remove linebreaks, replace with ' '
395
                            $comment = preg_replace('/[\\r\\n]/', ' ', $comment) ?? '';
396
                            // Remove # and * if more than twice in a row
397
                            $comment = preg_replace('/[#\\*]{2,}/', '', $comment) ?? '';
398
                            // Replace leading # (just if it exists) and add it again. Result: Every comment should be prefixed by a '#'.
399
                            $comment = preg_replace('/^[#\\*\\s]+/', '# ', $comment) ?? '';
400
                            // Masking HTML Tags: Replace < with &lt; and > with &gt;
401
                            $comment = htmlspecialchars($comment);
402
                            $HTML .= ' <i class="text-muted">' . trim($comment) . '</i>';
403
                        }
404
                    }
405
                }
406
                $HTML .= '</span>';
407
                if ($deeper) {
408
                    $HTML .= $this->ext_getObjTree($arr[$key . '.'] ?? [], $depth, $depthData, '', $arr[$key] ?? '', $alphaSort);
409
                }
410
            }
411
        }
412
        if ($HTML !== '') {
413
            $HTML = '<ul class="list-tree text-monospace">' . $HTML . '</ul>';
414
        }
415
416
        return $HTML;
417
    }
418
419
    /**
420
     * Find the originating template name for an array of line numbers (TypoScript setup only!)
421
     * Given an array of linenumbers the method will try to find the corresponding template where this line originated
422
     * The linenumber indicates the *last* lineNumber that is part of the template
423
     *
424
     * lineNumbers are in sync with the calculated lineNumbers '.ln..' in TypoScriptParser
425
     *
426
     * @param array $lnArr Array with linenumbers (might have some extra symbols, for example for unsetting) to be processed
427
     * @return string Imploded array of line number and template title
428
     */
429
    public function lineNumberToScript(array $lnArr)
430
    {
431
        // On the first call, construct the lnToScript array.
432
        if (!is_array($this->lnToScript)) {
433
            $this->lnToScript = [];
434
435
            // aggregatedTotalLineCount
436
            $c = 0;
437
            foreach ($this->hierarchyInfo as $templateNumber => $info) {
438
                // hierarchyInfo has the number of lines in configLines, but unfortunately this value
439
                // was calculated *before* processing of any INCLUDE instructions
440
                // for some yet unknown reason we have to add an extra +2 offset
441
                $linecountAfterIncludeProcessing = substr_count($this->config[$templateNumber], LF) + 2;
442
                $c += $linecountAfterIncludeProcessing;
443
                $this->lnToScript[$c] = $info['title'];
444
            }
445
        }
446
447
        foreach ($lnArr as $k => $ln) {
448
            foreach ($this->lnToScript as $endLn => $title) {
449
                if ($endLn >= (int)$ln) {
450
                    $lnArr[$k] = '"' . $title . '", ' . $ln;
451
                    break;
452
                }
453
            }
454
        }
455
456
        return implode('; ', $lnArr);
457
    }
458
459
    /**
460
     * @param array $arr
461
     * @param string $depth_in
462
     * @param string $searchString
463
     * @param array $keyArray
464
     * @return array
465
     * @throws Exception
466
     */
467
    public function ext_getSearchKeys($arr, $depth_in, $searchString, $keyArray)
468
    {
469
        $keyArr = [];
470
        foreach ($arr as $key => $value) {
471
            $key = preg_replace('/\\.$/', '', $key) ?? '';
472
            if (substr($key, -1) !== '.') {
473
                $keyArr[$key] = 1;
474
            }
475
        }
476
        if ($depth_in) {
477
            $depth_in = $depth_in . '.';
478
        }
479
        $searchPattern = '';
480
        if ($this->regexMode) {
481
            $searchPattern = '/' . addcslashes($searchString, '/') . '/';
482
            $matchResult = @preg_match($searchPattern, '');
483
            if ($matchResult === false) {
484
                throw new Exception(sprintf('Error evaluating regular expression "%s".', $searchPattern), 1446559458);
485
            }
486
        }
487
        foreach ($keyArr as $key => $value) {
488
            $depth = $depth_in . $key;
489
            $deeper = is_array($arr[$key . '.']);
490
            if ($this->regexMode) {
491
                // The value has matched
492
                if (preg_match($searchPattern, $arr[$key])) {
493
                    $this->tsbrowser_searchKeys[$depth] += 2;
494
                }
495
                // The key has matched
496
                if (preg_match($searchPattern, $key)) {
497
                    $this->tsbrowser_searchKeys[$depth] += 4;
498
                }
499
                // Just open this subtree if the parent key has matched the search
500
                if (preg_match($searchPattern, $depth_in)) {
501
                    $this->tsbrowser_searchKeys[$depth] = 1;
502
                }
503
            } else {
504
                // The value has matched
505
                if (stripos($arr[$key], $searchString) !== false) {
506
                    $this->tsbrowser_searchKeys[$depth] += 2;
507
                }
508
                // The key has matches
509
                if (stripos($key, $searchString) !== false) {
510
                    $this->tsbrowser_searchKeys[$depth] += 4;
511
                }
512
                // Just open this subtree if the parent key has matched the search
513
                if (stripos($depth_in, $searchString) !== false) {
514
                    $this->tsbrowser_searchKeys[$depth] = 1;
515
                }
516
            }
517
            if ($deeper) {
518
                $cS = count($this->tsbrowser_searchKeys);
519
                $keyArray = $this->ext_getSearchKeys($arr[$key . '.'], $depth, $searchString, $keyArray);
520
                if ($cS != count($this->tsbrowser_searchKeys)) {
521
                    $keyArray[$depth] = 1;
522
                }
523
            }
524
        }
525
        return $keyArray;
526
    }
527
528
    /**
529
     * @param int $pid
530
     * @return int
531
     */
532
    public function ext_getRootlineNumber($pid)
533
    {
534
        if ($pid) {
535
            foreach ($this->getRootLine() as $key => $val) {
536
                if ((int)$val['uid'] === (int)$pid) {
537
                    return (int)$key;
538
                }
539
            }
540
        }
541
        return -1;
542
    }
543
544
    /**
545
     * @param array $arr
546
     * @param string $depthData
547
     * @param array $keyArray
548
     * @param int $first
549
     * @return array
550
     */
551
    public function ext_getTemplateHierarchyArr($arr, $depthData, $keyArray, $first = 0)
552
    {
553
        $keyArr = [];
554
        foreach ($arr as $key => $value) {
555
            $key = preg_replace('/\\.$/', '', $key) ?? '';
556
            if (substr($key, -1) !== '.') {
557
                $keyArr[$key] = 1;
558
            }
559
        }
560
        $a = 0;
561
        $c = count($keyArr);
562
        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
563
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
564
        /** @var IconFactory $iconFactory */
565
        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
566
        foreach ($keyArr as $key => $value) {
567
            $HTML = '';
568
            $a++;
569
            $deeper = is_array($arr[$key . '.'] ?? false);
570
            $row = $arr[$key];
571
            $LN = $a == $c ? 'blank' : 'line';
572
            $BTM = $a == $c ? 'top' : '';
573
            $HTML .= $depthData;
574
            $alttext = '[' . $row['templateID'] . ']';
575
            $alttext .= $row['pid'] ? ' - ' . BackendUtility::getRecordPath($row['pid'], '1=1', 20) : '';
0 ignored issues
show
Bug introduced by
Are you sure TYPO3\CMS\Backend\Utilit...$row['pid'], '1=1', 20) of type array<integer,string>|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

575
            $alttext .= $row['pid'] ? ' - ' . /** @scrutinizer ignore-type */ BackendUtility::getRecordPath($row['pid'], '1=1', 20) : '';
Loading history...
576
            $icon = strpos($row['templateID'], 'sys') === 0
577
                ? '<span title="' . htmlspecialchars($alttext) . '">' . $iconFactory->getIconForRecord('sys_template', $row, Icon::SIZE_SMALL)->render() . '</span>'
578
                : '<span title="' . htmlspecialchars($alttext) . '">' . $iconFactory->getIcon('mimetypes-x-content-template-static', Icon::SIZE_SMALL)->render() . '</span>';
579
            if (in_array($row['templateID'], $this->clearList_const) || in_array($row['templateID'], $this->clearList_setup)) {
580
                $urlParameters = [
581
                    'id' => (int)GeneralUtility::_GP('id'),
582
                    'template' => $row['templateID']
583
                ];
584
                $aHref = (string)$uriBuilder->buildUriFromRoute('web_ts', $urlParameters);
585
                $A_B = '<a href="' . htmlspecialchars($aHref) . '">';
586
                $A_E = '</a>';
587
                if (GeneralUtility::_GP('template') == $row['templateID']) {
588
                    $A_B = '<strong>' . $A_B;
589
                    $A_E .= '</strong>';
590
                }
591
            } else {
592
                $A_B = '';
593
                $A_E = '';
594
            }
595
            $HTML .= ($first ? '' : '<span class="treeline-icon treeline-icon-join' . $BTM . '"></span>') . $icon . ' ' . $A_B
596
                . htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['title'], $GLOBALS['BE_USER']->uc['titleLen']))
597
                . $A_E . '&nbsp;&nbsp;';
598
            $RL = $this->ext_getRootlineNumber($row['pid']);
599
            $statusCheckedIcon = $iconFactory->getIcon('status-status-checked', Icon::SIZE_SMALL)->render();
600
            $keyArray[] = '<tr>
601
							<td class="nowrap">' . $HTML . '</td>
602
							<td align="center">' . ($row['root'] ? $statusCheckedIcon : '') . '</td>
603
							<td align="center">' . ($row['clConf'] ? $statusCheckedIcon : '') . '</td>
604
							<td align="center">' . ($row['clConst'] ? $statusCheckedIcon : '') . '</td>
605
							<td align="center">' . ($row['pid'] ?: '') . '</td>
606
							<td align="center">' . ($RL >= 0 ? $RL : '') . '</td>
607
						</tr>';
608
            if ($deeper) {
609
                $keyArray = $this->ext_getTemplateHierarchyArr($arr[$key . '.'], $depthData . ($first ? '' : '<span class="treeline-icon treeline-icon-' . $LN . '"></span>'), $keyArray);
610
            }
611
        }
612
        return $keyArray;
613
    }
614
615
    /**
616
     * Processes the flat array from TemplateService->hierarchyInfo
617
     * and turns it into a hierarchical array to show dependencies (used by TemplateAnalyzer)
618
     *
619
     * @param array $depthDataArr (empty array on external call)
620
     * @param int $pointer Element number (1! to count()) of $this->hierarchyInfo that should be processed.
621
     * @return array Processed hierachyInfo.
622
     */
623
    public function ext_process_hierarchyInfo(array $depthDataArr, &$pointer)
624
    {
625
        $parent = $this->hierarchyInfo[$pointer - 1]['templateParent'];
626
        while ($pointer > 0 && $this->hierarchyInfo[$pointer - 1]['templateParent'] == $parent) {
627
            $pointer--;
628
            $row = $this->hierarchyInfo[$pointer];
629
            $depthDataArr[$row['templateID']] = $row;
630
            unset($this->clearList_setup_temp[$row['templateID']]);
631
            unset($this->clearList_const_temp[$row['templateID']]);
632
            $this->templateTitles[$row['templateID']] = $row['title'];
633
            if ($row['templateID'] == ($this->hierarchyInfo[$pointer - 1]['templateParent'] ?? '')) {
634
                $depthDataArr[$row['templateID'] . '.'] = $this->ext_process_hierarchyInfo([], $pointer);
635
            }
636
        }
637
        return $depthDataArr;
638
    }
639
640
    /**
641
     * Get a single sys_template record attached to a single page.
642
     * If multiple template records are on this page, the first (order by sorting)
643
     * record will be returned, unless a specific template uid is specified via $templateUid
644
     *
645
     * @param int $pid The pid to select sys_template records from
646
     * @param int $templateUid Optional template uid
647
     * @return array|null Returns the template record or null if none was found
648
     */
649
    public function ext_getFirstTemplate($pid, $templateUid = 0)
650
    {
651
        if (empty($pid)) {
652
            return null;
653
        }
654
655
        // Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
656
        $queryBuilder = $this->getTemplateQueryBuilder($pid)
657
            ->setMaxResults(1);
658
        if ($templateUid) {
659
            $queryBuilder->andWhere(
660
                $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($templateUid, \PDO::PARAM_INT))
661
            );
662
        }
663
        $row = $queryBuilder->execute()->fetch();
664
        BackendUtility::workspaceOL('sys_template', $row);
665
666
        return $row;
667
    }
668
669
    /**
670
     * Get an array of all template records on a page.
671
     *
672
     * @param int $pid Pid to fetch sys_template records for
673
     * @return array[] Array of template records
674
     */
675
    public function ext_getAllTemplates($pid): array
676
    {
677
        if (empty($pid)) {
678
            return [];
679
        }
680
        $result = $this->getTemplateQueryBuilder($pid)->execute();
681
        $outRes = [];
682
        while ($row = $result->fetch()) {
683
            BackendUtility::workspaceOL('sys_template', $row);
684
            if (is_array($row)) {
685
                $outRes[] = $row;
686
            }
687
        }
688
        return $outRes;
689
    }
690
691
    /**
692
     * Internal helper method to prepare the query builder for
693
     * getting sys_template records from a given pid
694
     *
695
     * @param int $pid The pid to select sys_template records from
696
     * @return QueryBuilder Returns a QueryBuilder
697
     */
698
    protected function getTemplateQueryBuilder(int $pid): QueryBuilder
699
    {
700
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
701
            ->getQueryBuilderForTable('sys_template');
702
        $queryBuilder->getRestrictions()
703
            ->removeAll()
704
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
705
            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $GLOBALS['BE_USER']->workspace));
706
707
        $queryBuilder->select('*')
708
            ->from('sys_template')
709
            ->where(
710
                $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT))
711
            );
712
        if (!empty($GLOBALS['TCA']['sys_template']['ctrl']['sortby'])) {
713
            $queryBuilder->orderBy($GLOBALS['TCA']['sys_template']['ctrl']['sortby']);
714
        }
715
716
        return $queryBuilder;
717
    }
718
719
    /**
720
     * @param array $editConstArray
721
     */
722
    public function ext_categorizeEditableConstants($editConstArray)
723
    {
724
        // Runs through the available constants and fills the $this->categories array with pointers and priority-info
725
        foreach ($editConstArray as $constName => $constData) {
726
            if (!$constData['type']) {
727
                $constData['type'] = 'string';
728
            }
729
            $cats = explode(',', $constData['cat']);
730
            // if = only one category, while allows for many. We have agreed on only one category is the most basic way...
731
            foreach ($cats as $theCat) {
732
                $theCat = trim($theCat);
733
                if ($theCat) {
734
                    $this->categories[$theCat][$constName] = $constData['subcat'];
735
                }
736
            }
737
        }
738
    }
739
740
    /**
741
     * @return array
742
     */
743
    public function ext_getCategoryLabelArray()
744
    {
745
        // Returns array used for labels in the menu.
746
        $retArr = [];
747
        foreach ($this->categories as $k => $v) {
748
            if (!empty($v)) {
749
                $retArr[$k] = strtoupper($k) . ' (' . count($v) . ')';
750
            }
751
        }
752
        return $retArr;
753
    }
754
755
    /**
756
     * @param string $type
757
     * @return array
758
     */
759
    public function ext_getTypeData($type)
760
    {
761
        $retArr = [];
762
        $type = trim($type);
763
        if (!$type) {
764
            $retArr['type'] = 'string';
765
        } else {
766
            $m = strcspn($type, ' [');
767
            $retArr['type'] = strtolower(substr($type, 0, $m));
768
            $types = ['int' => 1, 'options' => 1, 'file' => 1, 'boolean' => 1, 'offset' => 1, 'user' => 1];
769
            if (isset($types[$retArr['type']])) {
770
                $p = trim(substr($type, $m));
771
                $reg = [];
772
                preg_match('/\\[(.*)\\]/', $p, $reg);
773
                $p = trim($reg[1] ?? '');
774
                if ($p) {
775
                    $retArr['paramstr'] = $p;
776
                    switch ($retArr['type']) {
777
                        case 'int':
778
                            if ($retArr['paramstr'][0] === '-') {
779
                                $retArr['params'] = GeneralUtility::intExplode('-', substr($retArr['paramstr'], 1));
780
                                $retArr['params'][0] = (int)('-' . $retArr['params'][0]);
781
                            } else {
782
                                $retArr['params'] = GeneralUtility::intExplode('-', $retArr['paramstr']);
783
                            }
784
                            $retArr['min'] = $retArr['params'][0];
785
                            $retArr['max'] = $retArr['params'][1];
786
                            $retArr['paramstr'] = $retArr['params'][0] . ' - ' . $retArr['params'][1];
787
                            break;
788
                        case 'options':
789
                            $retArr['params'] = explode(',', $retArr['paramstr']);
790
                            break;
791
                    }
792
                }
793
            }
794
        }
795
        return $retArr;
796
    }
797
798
    /**
799
     * @param array $params
800
     * @return array
801
     */
802
    public function ext_fNandV($params)
803
    {
804
        $fN = 'data[' . $params['name'] . ']';
805
        $idName = str_replace('.', '-', $params['name']);
806
        $fV = $params['value'];
807
        // Values entered from the constantsedit cannot be constants!	230502; removed \{ and set {
808
        if (preg_match('/^{[\\$][a-zA-Z0-9\\.]*}$/', trim($fV), $reg)) {
809
            $fV = '';
810
        }
811
        $fV = htmlspecialchars($fV);
812
        return [$fN, $fV, $params, $idName];
813
    }
814
815
    /**
816
     * This functions returns the HTML-code that creates the editor-layout of the module.
817
     *
818
     * @param array $theConstants
819
     * @param string $category
820
     * @return array
821
     */
822
    public function ext_printFields($theConstants, $category): array
823
    {
824
        reset($theConstants);
825
        $groupedOutput = [];
826
        $subcat = '';
827
        if (!empty($this->categories[$category]) && is_array($this->categories[$category])) {
828
            asort($this->categories[$category]);
829
            /** @var IconFactory $iconFactory */
830
            $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
831
            $categoryLoop = 0;
832
            foreach ($this->categories[$category] as $name => $type) {
833
                $params = $theConstants[$name];
834
                if (is_array($params)) {
835
                    if ($subcat !== (string)($params['subcat_name'] ?? '')) {
836
                        $categoryLoop++;
837
                        $subcat = (string)($params['subcat_name'] ?? '');
838
                        $subcat_name = $subcat ? (string)($this->constantParser->getSubCategories()[$subcat][0] ?? '') : 'Others';
839
                        $groupedOutput[$categoryLoop] = [
840
                            'label' => $subcat_name,
841
                            'fields' => []
842
                        ];
843
                    }
844
                    $label = $this->getLanguageService()->sL($params['label']);
845
                    $label_parts = explode(':', $label, 2);
846
                    if (count($label_parts) === 2) {
847
                        $head = trim($label_parts[0]);
848
                        $body = trim($label_parts[1]);
849
                    } else {
850
                        $head = trim($label_parts[0]);
851
                        $body = '';
852
                    }
853
                    $typeDat = $this->ext_getTypeData($params['type']);
854
                    $p_field = '';
855
                    $raname = substr(md5($params['name']), 0, 10);
856
                    $aname = '\'' . $raname . '\'';
857
                    [$fN, $fV, $params, $idName] = $this->ext_fNandV($params);
858
                    $idName = htmlspecialchars($idName);
859
                    $hint = '';
860
                    switch ($typeDat['type']) {
861
                        case 'int':
862
                        case 'int+':
863
                            $additionalAttributes = '';
864
                            if ($typeDat['paramstr'] ?? false) {
865
                                $hint = ' Range: ' . $typeDat['paramstr'];
866
                            } elseif ($typeDat['type'] === 'int+') {
867
                                $hint = ' Range: 0 - ';
868
                                $typeDat['min'] = 0;
869
                            } else {
870
                                $hint = ' (Integer)';
871
                            }
872
873
                            if (isset($typeDat['min'])) {
874
                                $additionalAttributes .= ' min="' . (int)$typeDat['min'] . '" ';
875
                            }
876
                            if (isset($typeDat['max'])) {
877
                                $additionalAttributes .= ' max="' . (int)$typeDat['max'] . '" ';
878
                            }
879
880
                            $p_field =
881
                                '<input class="form-control" id="' . $idName . '" type="number"'
882
                                . ' name="' . $fN . '" value="' . $fV . '" onChange="uFormUrl(' . $aname . ')"' . $additionalAttributes . ' />';
883
                            break;
884
                        case 'color':
885
                            $p_field = '
886
                                <input class="form-control formengine-colorpickerelement t3js-color-picker" type="text" id="input-' . $idName . '" rel="' . $idName .
887
                                '" name="' . $fN . '" value="' . $fV . '" onChange="uFormUrl(' . $aname . ')" />';
888
889
                            if (empty($this->inlineJavaScript[$typeDat['type']])) {
890
                                $this->inlineJavaScript[$typeDat['type']] = 'require([\'TYPO3/CMS/Backend/ColorPicker\'], function(ColorPicker){ColorPicker.initialize()});';
891
                            }
892
                            break;
893
                        case 'wrap':
894
                            $wArr = explode('|', $fV);
895
                            $p_field = '<div class="input-group">
896
                                            <input class="form-control form-control-adapt" type="text" id="' . $idName . '" name="' . $fN . '" value="' . $wArr[0] . '" onChange="uFormUrl(' . $aname . ')" />
897
                                            <span class="input-group-addon input-group-icon">|</span>
898
                                            <input class="form-control form-control-adapt" type="text" name="W' . $fN . '" value="' . $wArr[1] . '" onChange="uFormUrl(' . $aname . ')" />
899
                                         </div>';
900
                            break;
901
                        case 'offset':
902
                            $wArr = explode(',', $fV);
903
                            $labels = GeneralUtility::trimExplode(',', $typeDat['paramstr']);
904
                            $p_field = '<span class="input-group-addon input-group-icon">' . ($labels[0] ?: 'x') . '</span><input type="text" class="form-control form-control-adapt" name="' . $fN . '" value="' . $wArr[0] . '" onChange="uFormUrl(' . $aname . ')" />';
905
                            $p_field .= '<span class="input-group-addon input-group-icon">' . ($labels[1] ?: 'y') . '</span><input type="text" name="W' . $fN . '" value="' . $wArr[1] . '" class="form-control form-control-adapt" onChange="uFormUrl(' . $aname . ')" />';
906
                            $labelsCount = count($labels);
907
                            for ($aa = 2; $aa < $labelsCount; $aa++) {
908
                                if ($labels[$aa]) {
909
                                    $p_field .= '<span class="input-group-addon input-group-icon">' . $labels[$aa] . '</span><input type="text" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '" class="form-control form-control-adapt" onChange="uFormUrl(' . $aname . ')" />';
910
                                } else {
911
                                    $p_field .= '<input type="hidden" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '" />';
912
                                }
913
                            }
914
                            $p_field = '<div class="input-group">' . $p_field . '</div>';
915
                            break;
916
                        case 'options':
917
                            if (is_array($typeDat['params'])) {
918
                                $p_field = '';
919
                                foreach ($typeDat['params'] as $val) {
920
                                    $vParts = explode('=', $val, 2);
921
                                    $label = $vParts[0];
922
                                    $val = $vParts[1] ?? $vParts[0];
923
                                    // option tag:
924
                                    $sel = '';
925
                                    if ($val === $params['value']) {
926
                                        $sel = ' selected';
927
                                    }
928
                                    $p_field .= '<option value="' . htmlspecialchars($val) . '"' . $sel . '>' . $this->getLanguageService()->sL($label) . '</option>';
929
                                }
930
                                $p_field = '<select class="form-select" id="' . $idName . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
931
                            }
932
                            break;
933
                        case 'boolean':
934
                            $sel = $fV ? 'checked' : '';
935
                            $p_field =
936
                                '<input type="hidden" name="' . $fN . '" value="0" />'
937
                                . '<label class="btn btn-default btn-checkbox">'
938
                                . '<input id="' . $idName . '" type="checkbox" name="' . $fN . '" value="' . (($typeDat['paramstr'] ?? false) ?: 1) . '" ' . $sel . ' onClick="uFormUrl(' . $aname . ')" />'
939
                                . '<span class="t3-icon fa"></span>'
940
                                . '</label>';
941
                            break;
942
                        case 'comment':
943
                            $sel = $fV ? '' : 'checked';
944
                            $p_field =
945
                                '<input type="hidden" name="' . $fN . '" value="" />'
946
                                . '<label class="btn btn-default btn-checkbox">'
947
                                . '<input id="' . $idName . '" type="checkbox" name="' . $fN . '" value="1" ' . $sel . ' onClick="uFormUrl(' . $aname . ')" />'
948
                                . '<span class="t3-icon fa"></span>'
949
                                . '</label>';
950
                            break;
951
                        case 'file':
952
                            // extensionlist
953
                            $extList = $typeDat['paramstr'];
954
                            if ($extList === 'IMAGE_EXT') {
955
                                $extList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
956
                            }
957
                            $p_field = '<option value="">(' . $extList . ')</option>';
958
                            if (trim($params['value'])) {
959
                                $val = $params['value'];
960
                                $p_field .= '<option value=""></option>';
961
                                $p_field .= '<option value="' . htmlspecialchars($val) . '" selected>' . $val . '</option>';
962
                            }
963
                            $p_field = '<select class="form-select" id="' . $idName . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
964
                            break;
965
                        case 'user':
966
                            $userFunction = $typeDat['paramstr'];
967
                            $userFunctionParams = ['fieldName' => $fN, 'fieldValue' => $fV];
968
                            $p_field = GeneralUtility::callUserFunction($userFunction, $userFunctionParams, $this);
969
                            break;
970
                        default:
971
                            $p_field = '<input class="form-control" id="' . $idName . '" type="text" name="' . $fN . '" value="' . $fV . '"'
972
                                . ' onChange="uFormUrl(' . $aname . ')" />';
973
                    }
974
                    // Define default names and IDs
975
                    $userTyposcriptID = 'userTS-' . $idName;
976
                    $defaultTyposcriptID = 'defaultTS-' . $idName;
977
                    $userTyposcriptStyle = '';
978
                    // Set the default styling options
979
                    if (isset($this->objReg[$params['name']])) {
980
                        $checkboxValue = 'checked';
981
                        $defaultTyposcriptStyle = 'style="display:none;"';
982
                    } else {
983
                        $checkboxValue = '';
984
                        $userTyposcriptStyle = 'style="display:none;"';
985
                        $defaultTyposcriptStyle = '';
986
                    }
987
                    $deleteIconHTML =
988
                        '<button type="button" class="btn btn-default t3js-toggle" data-bs-toggle="undo" rel="' . $idName . '">'
989
                            . '<span title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.deleteTitle')) . '">'
990
                                . $iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render()
991
                            . '</span>'
992
                        . '</button>';
993
                    $editIconHTML =
994
                        '<button type="button" class="btn btn-default t3js-toggle" data-bs-toggle="edit"  rel="' . $idName . '">'
995
                            . '<span title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.editTitle')) . '">'
996
                                . $iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render()
997
                            . '</span>'
998
                        . '</button>';
999
                    $constantCheckbox = '<input type="hidden" name="check[' . $params['name'] . ']" id="check-' . $idName . '" value="' . $checkboxValue . '"/>';
1000
                    // If there's no default value for the field, use a static label.
1001
                    if (!$params['default_value']) {
1002
                        $params['default_value'] = '[Empty]';
1003
                    }
1004
                    $constantDefaultRow =
1005
                        '<div class="input-group defaultTS" id="' . $defaultTyposcriptID . '" ' . $defaultTyposcriptStyle . '>'
1006
                            . '<span class="input-group-btn">' . $editIconHTML . '</span>'
1007
                            . '<input class="form-control" type="text" placeholder="' . htmlspecialchars($params['default_value']) . '" readonly>'
1008
                        . '</div>';
1009
                    $constantEditRow =
1010
                        '<div class="input-group userTS" id="' . $userTyposcriptID . '" ' . $userTyposcriptStyle . '>'
1011
                            . '<span class="input-group-btn">' . $deleteIconHTML . '</span>'
1012
                            . $p_field
1013
                        . '</div>';
1014
                    $constantData =
1015
                        $constantCheckbox
1016
                        . $constantEditRow
1017
                        . $constantDefaultRow;
1018
1019
                    $groupedOutput[$categoryLoop]['items'][] = [
1020
                        'identifier' => $raname,
1021
                        'label' => $head,
1022
                        'name' => $params['name'],
1023
                        'description' => $body,
1024
                        'hint' => $hint,
1025
                        'data' => $constantData
1026
                    ];
1027
                } else {
1028
                    debug('Error. Constant did not exist. Should not happen.');
1029
                }
1030
            }
1031
        }
1032
        return $groupedOutput;
1033
    }
1034
1035
    /***************************
1036
     *
1037
     * Processing input values
1038
     *
1039
     ***************************/
1040
    /**
1041
     * @param string $constants
1042
     */
1043
    public function ext_regObjectPositions($constants)
1044
    {
1045
        // This runs through the lines of the constants-field of the active template and registers the constants-names
1046
        // and line positions in an array, $this->objReg
1047
        $this->raw = explode(LF, $constants);
1048
        $this->rawP = 0;
1049
        // Resetting the objReg if the divider is found!!
1050
        $this->objReg = [];
1051
        $this->ext_regObjects('');
1052
    }
1053
1054
    /**
1055
     * @param string $pre
1056
     */
1057
    public function ext_regObjects($pre)
1058
    {
1059
        // Works with regObjectPositions. "expands" the names of the TypoScript objects
1060
        while (isset($this->raw[$this->rawP])) {
1061
            $line = ltrim($this->raw[$this->rawP]);
1062
            $this->rawP++;
1063
            if ($line) {
1064
                if ($line[0] === '[') {
1065
                } elseif (strcspn($line, '}#/') != 0) {
1066
                    $varL = strcspn($line, ' {=<');
1067
                    $var = substr($line, 0, $varL);
1068
                    $line = ltrim(substr($line, $varL));
1069
                    switch ($line[0]) {
1070
                        case '=':
1071
                            $this->objReg[$pre . $var] = $this->rawP - 1;
1072
                            break;
1073
                        case '{':
1074
                            $this->ext_inBrace++;
1075
                            $this->ext_regObjects($pre . $var . '.');
1076
                            break;
1077
                    }
1078
                    $this->lastComment = '';
1079
                } elseif ($line[0] === '}') {
1080
                    $this->lastComment = '';
1081
                    $this->ext_inBrace--;
1082
                    if ($this->ext_inBrace < 0) {
1083
                        $this->ext_inBrace = 0;
1084
                    } else {
1085
                        break;
1086
                    }
1087
                }
1088
            }
1089
        }
1090
    }
1091
1092
    /**
1093
     * @param string $key
1094
     * @param string $var
1095
     */
1096
    public function ext_putValueInConf($key, $var)
1097
    {
1098
        // Puts the value $var to the TypoScript value $key in the current lines of the templates.
1099
        // If the $key is not found in the template constants field, a new line is inserted in the bottom.
1100
        $theValue = ' ' . trim($var);
1101
        if (isset($this->objReg[$key])) {
1102
            $lineNum = $this->objReg[$key];
1103
            $parts = explode('=', $this->raw[$lineNum], 2);
1104
            if (count($parts) === 2) {
1105
                $parts[1] = $theValue;
1106
            }
1107
            $this->raw[$lineNum] = implode('=', $parts);
1108
        } else {
1109
            $this->raw[] = $key . ' =' . $theValue;
1110
        }
1111
        $this->changed = true;
1112
    }
1113
1114
    /**
1115
     * @param string $key
1116
     */
1117
    public function ext_removeValueInConf($key)
1118
    {
1119
        // Removes the value in the configuration
1120
        if (isset($this->objReg[$key])) {
1121
            $lineNum = $this->objReg[$key];
1122
            unset($this->raw[$lineNum]);
1123
        }
1124
        $this->changed = true;
1125
    }
1126
1127
    /**
1128
     * @param array $arr
1129
     * @param array $settings
1130
     * @return array
1131
     */
1132
    public function ext_depthKeys($arr, $settings)
1133
    {
1134
        $tsbrArray = [];
1135
        foreach ($arr as $theK => $theV) {
1136
            $theKeyParts = explode('.', $theK);
1137
            $depth = '';
1138
            $c = count($theKeyParts);
1139
            $a = 0;
1140
            foreach ($theKeyParts as $p) {
1141
                $a++;
1142
                $depth .= ($depth ? '.' : '') . $p;
1143
                $tsbrArray[$depth] = $c == $a ? $theV : 1;
1144
            }
1145
        }
1146
        // Modify settings
1147
        foreach ($tsbrArray as $theK => $theV) {
1148
            if ($theV) {
1149
                $settings[$theK] = 1;
1150
            } else {
1151
                unset($settings[$theK]);
1152
            }
1153
        }
1154
        return $settings;
1155
    }
1156
1157
    /**
1158
     * Process input
1159
     *
1160
     * @param array $http_post_vars
1161
     * @param array $http_post_files (not used anymore)
1162
     * @param array $theConstants
1163
     * @param array $tplRow Not used
1164
     */
1165
    public function ext_procesInput($http_post_vars, $http_post_files, $theConstants, $tplRow)
1166
    {
1167
        $data = $http_post_vars['data'];
1168
        $check = $http_post_vars['check'];
1169
        $Wdata = $http_post_vars['Wdata'] ?? [];
1170
        $W2data = $http_post_vars['W2data'] ?? [];
1171
        $W3data = $http_post_vars['W3data'] ?? [];
1172
        $W4data = $http_post_vars['W4data'] ?? [];
1173
        $W5data = $http_post_vars['W5data'] ?? [];
1174
        if (is_array($data)) {
1175
            foreach ($data as $key => $var) {
1176
                if (isset($theConstants[$key])) {
1177
                    // If checkbox is set, update the value
1178
                    if (isset($check[$key])) {
1179
                        // Exploding with linebreak, just to make sure that no multiline input is given!
1180
                        [$var] = explode(LF, $var);
1181
                        $typeDat = $this->ext_getTypeData($theConstants[$key]['type']);
1182
                        switch ($typeDat['type']) {
1183
                            case 'int':
1184
                                if ($typeDat['paramstr']) {
1185
                                    $var = MathUtility::forceIntegerInRange((int)$var, $typeDat['params'][0], $typeDat['params'][1]);
1186
                                } else {
1187
                                    $var = (int)$var;
1188
                                }
1189
                                break;
1190
                            case 'int+':
1191
                                $var = max(0, (int)$var);
1192
                                break;
1193
                            case 'color':
1194
                                $col = [];
1195
                                if ($var) {
1196
                                    $var = preg_replace('/[^A-Fa-f0-9]*/', '', $var) ?? '';
1197
                                    $useFulHex = strlen($var) > 3;
1198
                                    $col[] = (int)hexdec($var[0]);
1199
                                    $col[] = (int)hexdec($var[1]);
1200
                                    $col[] = (int)hexdec($var[2]);
1201
                                    if ($useFulHex) {
1202
                                        $col[] = (int)hexdec($var[3]);
1203
                                        $col[] = (int)hexdec($var[4]);
1204
                                        $col[] = (int)hexdec($var[5]);
1205
                                    }
1206
                                    $var = substr('0' . dechex($col[0]), -1) . substr('0' . dechex($col[1]), -1) . substr('0' . dechex($col[2]), -1);
1207
                                    if ($useFulHex) {
1208
                                        $var .= substr('0' . dechex($col[3]), -1) . substr('0' . dechex($col[4]), -1) . substr('0' . dechex($col[5]), -1);
1209
                                    }
1210
                                    $var = '#' . strtoupper($var);
1211
                                }
1212
                                break;
1213
                            case 'comment':
1214
                                if ($var) {
1215
                                    $var = '';
1216
                                } else {
1217
                                    $var = '#';
1218
                                }
1219
                                break;
1220
                            case 'wrap':
1221
                                if (isset($Wdata[$key])) {
1222
                                    $var .= '|' . $Wdata[$key];
1223
                                }
1224
                                break;
1225
                            case 'offset':
1226
                                if (isset($Wdata[$key])) {
1227
                                    $var = (int)$var . ',' . (int)$Wdata[$key];
1228
                                    if (isset($W2data[$key])) {
1229
                                        $var .= ',' . (int)$W2data[$key];
1230
                                        if (isset($W3data[$key])) {
1231
                                            $var .= ',' . (int)$W3data[$key];
1232
                                            if (isset($W4data[$key])) {
1233
                                                $var .= ',' . (int)$W4data[$key];
1234
                                                if (isset($W5data[$key])) {
1235
                                                    $var .= ',' . (int)$W5data[$key];
1236
                                                }
1237
                                            }
1238
                                        }
1239
                                    }
1240
                                }
1241
                                break;
1242
                            case 'boolean':
1243
                                if ($var) {
1244
                                    $var = $typeDat['paramstr'] ?: 1;
1245
                                }
1246
                                break;
1247
                        }
1248
                        if ((string)$theConstants[$key]['value'] !== (string)$var) {
1249
                            // Put value in, if changed.
1250
                            $this->ext_putValueInConf($key, $var);
1251
                        }
1252
                        // Remove the entry because it has been "used"
1253
                        unset($check[$key]);
1254
                    } else {
1255
                        $this->ext_removeValueInConf($key);
1256
                    }
1257
                }
1258
            }
1259
        }
1260
        // Remaining keys in $check indicates fields that are just clicked "on" to be edited.
1261
        // Therefore we get the default value and puts that in the template as a start...
1262
        foreach ($check ?? [] as $key => $var) {
1263
            if (isset($theConstants[$key])) {
1264
                $dValue = $theConstants[$key]['default_value'];
1265
                $this->ext_putValueInConf($key, $dValue);
1266
            }
1267
        }
1268
    }
1269
1270
    /**
1271
     * @param int $id
1272
     * @param string $perms_clause
1273
     * @return array
1274
     */
1275
    public function ext_prevPageWithTemplate($id, $perms_clause)
1276
    {
1277
        $rootLine = BackendUtility::BEgetRootLine($id, $perms_clause ? ' AND ' . $perms_clause : '');
1278
        foreach ($rootLine as $p) {
1279
            if ($this->ext_getFirstTemplate($p['uid'])) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->ext_getFirstTemplate($p['uid']) targeting TYPO3\CMS\Core\TypoScrip...:ext_getFirstTemplate() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1280
                return $p;
1281
            }
1282
        }
1283
        return [];
1284
    }
1285
1286
    /**
1287
     * Is set by runThroughTemplates(), previously set via TemplateAnalyzerModuleFunctionController from the outside
1288
     *
1289
     * @return array
1290
     */
1291
    protected function getRootLine()
1292
    {
1293
        return is_array($this->absoluteRootLine) ? $this->absoluteRootLine : [];
0 ignored issues
show
introduced by
The condition is_array($this->absoluteRootLine) is always true.
Loading history...
1294
    }
1295
1296
    /**
1297
     * @return LanguageService
1298
     */
1299
    protected function getLanguageService()
1300
    {
1301
        return $GLOBALS['LANG'];
1302
    }
1303
}
1304