GroupElement::render()   F
last analyzed

Complexity

Conditions 41
Paths > 20000

Size

Total Lines 271
Code Lines 219

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 219
dl 0
loc 271
rs 0
c 0
b 0
f 0
cc 41
nc 835648
nop 0

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\Backend\Form\Element;
17
18
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19
use TYPO3\CMS\Core\Imaging\Icon;
20
use TYPO3\CMS\Core\Localization\LanguageService;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
use TYPO3\CMS\Core\Utility\MathUtility;
23
use TYPO3\CMS\Core\Utility\StringUtility;
24
25
/**
26
 * Generation of elements of the type "group"
27
 */
28
class GroupElement extends AbstractFormElement
29
{
30
    /**
31
     * Default field information enabled for this element.
32
     *
33
     * @var array
34
     */
35
    protected $defaultFieldInformation = [
36
        'tcaDescription' => [
37
            'renderType' => 'tcaDescription',
38
        ],
39
    ];
40
41
    /**
42
     * Default field controls for this element.
43
     *
44
     * @var array
45
     */
46
    protected $defaultFieldControl = [
47
        'elementBrowser' => [
48
            'renderType' => 'elementBrowser',
49
        ],
50
        'insertClipboard' => [
51
            'renderType' => 'insertClipboard',
52
            'after' => [ 'elementBrowser' ],
53
        ],
54
        'editPopup' => [
55
            'renderType' => 'editPopup',
56
            'disabled' => true,
57
            'after' => [ 'insertClipboard' ],
58
        ],
59
        'addRecord' => [
60
            'renderType' => 'addRecord',
61
            'disabled' => true,
62
            'after' => [ 'editPopup' ],
63
        ],
64
        'listModule' => [
65
            'renderType' => 'listModule',
66
            'disabled' => true,
67
            'after' => [ 'addRecord' ],
68
        ],
69
    ];
70
71
    /**
72
     * Default field wizards for this element
73
     *
74
     * @var array
75
     */
76
    protected $defaultFieldWizard = [
77
        'tableList' => [
78
            'renderType' => 'tableList',
79
        ],
80
        'recordsOverview' => [
81
            'renderType' => 'recordsOverview',
82
            'after' => [ 'tableList' ],
83
        ],
84
        'localizationStateSelector' => [
85
            'renderType' => 'localizationStateSelector',
86
            'after' => [ 'recordsOverview' ],
87
        ],
88
        'otherLanguageContent' => [
89
            'renderType' => 'otherLanguageContent',
90
            'after' => [ 'localizationStateSelector' ],
91
        ],
92
        'defaultLanguageDifferences' => [
93
            'renderType' => 'defaultLanguageDifferences',
94
            'after' => [ 'otherLanguageContent' ],
95
        ],
96
    ];
97
98
    /**
99
     * This will render a selector box into which elements from either
100
     * the file system or database can be inserted. Relations.
101
     *
102
     * @return array As defined in initializeResultArray() of AbstractNode
103
     * @throws \RuntimeException
104
     */
105
    public function render()
106
    {
107
        $languageService = $this->getLanguageService();
108
        $backendUser = $this->getBackendUserAuthentication();
109
        $resultArray = $this->initializeResultArray();
110
111
        $table = $this->data['tableName'];
112
        $fieldName = $this->data['fieldName'];
113
        $row = $this->data['databaseRow'];
114
        $parameterArray = $this->data['parameterArray'];
115
        $config = $parameterArray['fieldConf']['config'];
116
        $elementName = $parameterArray['itemFormElName'];
117
118
        $selectedItems = $parameterArray['itemFormElValue'];
119
        $selectedItemsCount = count($selectedItems);
120
121
        $maxItems = $config['maxitems'];
122
        $autoSizeMax = MathUtility::forceIntegerInRange($config['autoSizeMax'] ?? 0, 0);
123
        $size = 5;
124
        if (isset($config['size'])) {
125
            $size = (int)$config['size'];
126
        }
127
        if ($autoSizeMax >= 1) {
128
            $size = MathUtility::forceIntegerInRange($selectedItemsCount + 1, MathUtility::forceIntegerInRange($size, 1), $autoSizeMax);
129
        }
130
131
        $internalType = (string)$config['internal_type'];
132
        $maxTitleLength = $backendUser->uc['titleLen'];
133
134
        $listOfSelectedValues = [];
135
        $selectorOptionsHtml = [];
136
        if ($internalType === 'folder') {
137
            foreach ($selectedItems as $selectedItem) {
138
                $folder = $selectedItem['folder'];
139
                $listOfSelectedValues[] = $folder;
140
                $selectorOptionsHtml[] =
141
                    '<option value="' . htmlspecialchars($folder) . '" title="' . htmlspecialchars($folder) . '">'
142
                        . htmlspecialchars($folder)
143
                    . '</option>';
144
            }
145
        } elseif ($internalType === 'db') {
146
            foreach ($selectedItems as $selectedItem) {
147
                $tableWithUid = $selectedItem['table'] . '_' . $selectedItem['uid'];
148
                $listOfSelectedValues[] = $tableWithUid;
149
                $title = $selectedItem['title'];
150
                if (empty($title)) {
151
                    $title = '[' . $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title') . ']';
152
                }
153
                $shortenedTitle = GeneralUtility::fixed_lgd_cs($title, $maxTitleLength);
154
                $selectorOptionsHtml[] =
155
                    '<option value="' . htmlspecialchars($tableWithUid) . '" title="' . htmlspecialchars($title) . '">'
156
                        . htmlspecialchars($this->appendValueToLabelInDebugMode($shortenedTitle, $tableWithUid))
157
                    . '</option>';
158
            }
159
        } else {
160
            throw new \RuntimeException(
161
                'internal_type missing on type="group" field',
162
                1485007097
163
            );
164
        }
165
166
        $fieldInformationResult = $this->renderFieldInformation();
167
        $fieldInformationHtml = $fieldInformationResult['html'];
168
        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
169
170
        if (isset($config['readOnly']) && $config['readOnly']) {
171
            // Return early if element is read only
172
            $html = [];
173
            $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
174
            $html[] =   $fieldInformationHtml;
175
            $html[] =   '<div class="form-wizards-wrap">';
176
            $html[] =       '<div class="form-wizards-element">';
177
            $html[] =           '<select';
178
            $html[] =               ' size="' . $size . '"';
179
            $html[] =               ' disabled="disabled"';
180
            $html[] =               ' class="form-select"';
181
            $html[] =               ($maxItems !== 1 && $size !== 1) ? ' multiple="multiple"' : '';
182
            $html[] =           '>';
183
            $html[] =               implode(LF, $selectorOptionsHtml);
184
            $html[] =           '</select>';
185
            $html[] =       '</div>';
186
            $html[] =       '<div class="form-wizards-items-aside">';
187
            $html[] =       '</div>';
188
            $html[] =   '</div>';
189
            $html[] = '</div>';
190
            $resultArray['html'] = implode(LF, $html);
191
            return $resultArray;
192
        }
193
194
        // Need some information if in flex form scope for the suggest element
195
        $dataStructureIdentifier = '';
196
        $flexFormSheetName = '';
197
        $flexFormFieldName = '';
198
        $flexFormContainerName = '';
199
        $flexFormContainerFieldName = '';
200
        if ($this->data['processedTca']['columns'][$fieldName]['config']['type'] === 'flex') {
201
            $flexFormConfig = $this->data['processedTca']['columns'][$fieldName];
202
            $dataStructureIdentifier = $flexFormConfig['config']['dataStructureIdentifier'];
203
            if (!isset($flexFormConfig['config']['dataStructureIdentifier'])) {
204
                throw new \RuntimeException(
205
                    'A data structure identifier must be set in [\'config\'] part of a flex form.'
206
                    . ' This is usually added by TcaFlexPrepare data processor',
207
                    1485206970
208
                );
209
            }
210
            if (isset($this->data['flexFormSheetName'])) {
211
                $flexFormSheetName = $this->data['flexFormSheetName'];
212
            }
213
            if (isset($this->data['flexFormFieldName'])) {
214
                $flexFormFieldName = $this->data['flexFormFieldName'];
215
            }
216
            if (isset($this->data['flexFormContainerName'])) {
217
                $flexFormContainerName = $this->data['flexFormContainerName'];
218
            }
219
            if (isset($this->data['flexFormContainerFieldName'])) {
220
                $flexFormContainerFieldName = $this->data['flexFormContainerFieldName'];
221
            }
222
        }
223
        // Get minimum characters for suggest from TCA and override by TsConfig
224
        $suggestMinimumCharacters = 0;
225
        if (isset($config['suggestOptions']['default']['minimumCharacters'])) {
226
            $suggestMinimumCharacters = (int)$config['suggestOptions']['default']['minimumCharacters'];
227
        }
228
        if (isset($parameterArray['fieldTSConfig']['suggest.']['default.']['minimumCharacters'])) {
229
            $suggestMinimumCharacters = (int)$parameterArray['fieldTSConfig']['suggest.']['default.']['minimumCharacters'];
230
        }
231
        $suggestMinimumCharacters = $suggestMinimumCharacters > 0 ? $suggestMinimumCharacters : 2;
232
233
        $itemCanBeSelectedMoreThanOnce = !empty($config['multiple']);
234
235
        $showMoveIcons = true;
236
        if (isset($config['hideMoveIcons']) && $config['hideMoveIcons']) {
237
            $showMoveIcons = false;
238
        }
239
        $showDeleteControl = true;
240
        if (isset($config['hideDeleteIcon']) && $config['hideDeleteIcon']) {
241
            $showDeleteControl = false;
242
        }
243
244
        $fieldId = StringUtility::getUniqueId('tceforms-multiselect-');
245
246
        $selectorAttributes = [
247
            'id' => $fieldId,
248
            'data-formengine-input-name' => htmlspecialchars($elementName),
249
            'data-maxitems' => (string)$maxItems,
250
            'size' => (string)$size,
251
        ];
252
        $selectorAttributes['class'] = 'form-select';
253
        if ($maxItems !== 1 && $size !== 1) {
254
            $selectorAttributes['multiple'] = 'multiple';
255
        }
256
257
        $fieldControlResult = $this->renderFieldControl();
258
        $fieldControlHtml = $fieldControlResult['html'];
259
        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
260
261
        $fieldWizardResult = $this->renderFieldWizard();
262
        $fieldWizardHtml = $fieldWizardResult['html'];
263
        $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
264
265
        $html = [];
266
        $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
267
        $html[] =   $fieldInformationHtml;
268
        $html[] =   '<div class="form-wizards-wrap">';
269
        if ($internalType === 'db' && (!isset($config['hideSuggest']) || (bool)$config['hideSuggest'] !== true)) {
270
            $html[] =   '<div class="form-wizards-items-top">';
271
            $html[] =       '<div class="autocomplete t3-form-suggest-container">';
272
            $html[] =           '<div class="input-group">';
273
            $html[] =               '<span class="input-group-addon">';
274
            $html[] =                   $this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render();
275
            $html[] =               '</span>';
276
            $html[] =               '<input type="search" class="t3-form-suggest form-control"';
277
            $html[] =                   ' placeholder="' . $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.findRecord') . '"';
278
            $html[] =                   ' data-fieldname="' . htmlspecialchars($fieldName) . '"';
279
            $html[] =                   ' data-tablename="' . htmlspecialchars($table) . '"';
280
            $html[] =                   ' data-field="' . htmlspecialchars($elementName) . '"';
281
            $html[] =                   ' data-uid="' . htmlspecialchars($this->data['databaseRow']['uid']) . '"';
282
            $html[] =                   ' data-pid="' . htmlspecialchars($this->data['parentPageRow']['uid'] ?? 0) . '"';
283
            $html[] =                   ' data-fieldtype="' . htmlspecialchars($config['type']) . '"';
284
            $html[] =                   ' data-minchars="' . htmlspecialchars((string)$suggestMinimumCharacters) . '"';
285
            $html[] =                   ' data-datastructureidentifier="' . htmlspecialchars($dataStructureIdentifier) . '"';
286
            $html[] =                   ' data-flexformsheetname="' . htmlspecialchars($flexFormSheetName) . '"';
287
            $html[] =                   ' data-flexformfieldname="' . htmlspecialchars($flexFormFieldName) . '"';
288
            $html[] =                   ' data-flexformcontainername="' . htmlspecialchars($flexFormContainerName) . '"';
289
            $html[] =                   ' data-flexformcontainerfieldname="' . htmlspecialchars($flexFormContainerFieldName) . '"';
290
            $html[] =               '/>';
291
            $html[] =           '</div>';
292
            $html[] =       '</div>';
293
            $html[] =   '</div>';
294
        }
295
        $html[] =       '<div class="form-wizards-element">';
296
        $html[] =           '<input type="hidden" class="t3js-group-hidden-field" data-formengine-input-name="' . htmlspecialchars($elementName) . '" value="' . $itemCanBeSelectedMoreThanOnce . '" />';
297
        $html[] =           '<select ' . GeneralUtility::implodeAttributes($selectorAttributes, true) . '>';
298
        $html[] =               implode(LF, $selectorOptionsHtml);
299
        $html[] =           '</select>';
300
        $html[] =       '</div>';
301
        $html[] =       '<div class="form-wizards-items-aside">';
302
        $html[] =           '<div class="btn-group-vertical">';
303
        if ($maxItems > 1 && $size >=5 && $showMoveIcons) {
304
            $html[] =           '<a href="#"';
305
            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-top"';
306
            $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
307
            $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
308
            $html[] =           '>';
309
            $html[] =               $this->iconFactory->getIcon('actions-move-to-top', Icon::SIZE_SMALL)->render();
310
            $html[] =           '</a>';
311
        }
312
        if ($maxItems > 1 && $size > 1 && $showMoveIcons) {
313
            $html[] =           '<a href="#"';
314
            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-up"';
315
            $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
316
            $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
317
            $html[] =           '>';
318
            $html[] =               $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render();
319
            $html[] =           '</a>';
320
            $html[] =           '<a href="#"';
321
            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-down"';
322
            $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
323
            $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
324
            $html[] =           '>';
325
            $html[] =               $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render();
326
            $html[] =           '</a>';
327
        }
328
        if ($maxItems > 1 && $size >= 5 && $showMoveIcons) {
329
            $html[] =           '<a href="#"';
330
            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-bottom"';
331
            $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
332
            $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
333
            $html[] =           '>';
334
            $html[] =               $this->iconFactory->getIcon('actions-move-to-bottom', Icon::SIZE_SMALL)->render();
335
            $html[] =           '</a>';
336
        }
337
        if ($showDeleteControl) {
338
            $html[] =           '<a href="#"';
339
            $html[] =               ' class="btn btn-default t3js-btn-option t3js-btn-removeoption t3js-revert-unique"';
340
            $html[] =               ' data-fieldname="' . htmlspecialchars($elementName) . '"';
341
            $html[] =               ' data-uid="' . htmlspecialchars($row['uid']) . '"';
342
            $html[] =               ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
343
            $html[] =           '>';
344
            $html[] =               $this->iconFactory->getIcon('actions-selection-delete', Icon::SIZE_SMALL)->render();
345
            $html[] =           '</a>';
346
        }
347
        $html[] =           '</div>';
348
        $html[] =       '</div>';
349
        $html[] =       '<div class="form-wizards-items-aside">';
350
        $html[] =           '<div class="btn-group-vertical">';
351
        $html[] =               $fieldControlHtml;
352
        $html[] =           '</div>';
353
        $html[] =       '</div>';
354
        if (!empty($fieldWizardHtml)) {
355
            $html[] = '<div class="form-wizards-items-bottom">';
356
            $html[] = $fieldWizardHtml;
357
            $html[] = '</div>';
358
        }
359
        $html[] =   '</div>';
360
        $html[] =   '<input type="hidden"';
361
        $html[] =       ' data-formengine-validation-rules="' . htmlspecialchars($this->getValidationDataAsJsonString($config)) . '"';
362
        $html[] =       ' name="' . htmlspecialchars($elementName) . '"';
363
        $html[] =       ' value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '"';
364
        $html[] =       ' onchange="' . htmlspecialchars(implode('', $parameterArray['fieldChangeFunc'])) . '"';
365
        $html[] =   ' />';
366
        $html[] = '</div>';
367
368
        $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/GroupElement' => '
369
            function(GroupElement) {
370
                new GroupElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
371
            }'
372
        ];
373
374
        $resultArray['html'] = implode(LF, $html);
375
        return $resultArray;
376
    }
377
378
    /**
379
     * @return BackendUserAuthentication
380
     */
381
    protected function getBackendUserAuthentication()
382
    {
383
        return $GLOBALS['BE_USER'];
384
    }
385
386
    /**
387
     * @return LanguageService
388
     */
389
    protected function getLanguageService()
390
    {
391
        return $GLOBALS['LANG'];
392
    }
393
}
394