Passed
Push — master ( 3e02b0...e0a47f )
by
unknown
16:25
created

InfoPageTyposcriptConfigController   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 411
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 45
eloc 238
c 0
b 0
f 0
dl 0
loc 411
rs 8.8

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getBackendUser() 0 3 1
A modMenu() 0 26 2
B getList() 0 31 7
A __construct() 0 4 1
A getFluidTemplateObject() 0 11 1
A getCodeMirrorHtml() 0 24 1
A setInPageArray() 0 17 4
A init() 0 8 1
A getTextareaMarkup() 0 5 1
A extractLinesFromTSConfig() 0 14 3
A getLanguageService() 0 3 1
A getOverviewOfPagesUsingTSConfig() 0 25 2
F main() 0 140 20

How to fix   Complexity   

Complex Class

Complex classes like InfoPageTyposcriptConfigController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use InfoPageTyposcriptConfigController, and based on these observations, apply Extract Interface, too.

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\Info\Controller;
17
18
use Psr\Http\Message\ServerRequestInterface;
19
use TYPO3\CMS\Backend\Routing\UriBuilder;
20
use TYPO3\CMS\Backend\Utility\BackendUtility;
21
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22
use TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader;
23
use TYPO3\CMS\Core\Database\ConnectionPool;
24
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
25
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
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\Page\PageRenderer;
30
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
31
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
use TYPO3\CMS\Core\Utility\MathUtility;
34
use TYPO3\CMS\Fluid\View\StandaloneView;
35
36
/**
37
 * Page TSconfig viewer in Web -> Info
38
 * @internal This class is a specific Backend controller implementation and is not part of the TYPO3's Core API.
39
 */
40
class InfoPageTyposcriptConfigController
41
{
42
    protected IconFactory $iconFactory;
43
    protected UriBuilder $uriBuilder;
44
45
    /**
46
     * @var StandaloneView
47
     */
48
    protected $view;
49
50
    /**
51
     * @var InfoModuleController Contains a reference to the parent calling object
52
     */
53
    protected $pObj;
54
55
    /**
56
     * @var int Value of the GET/POST var 'id'
57
     */
58
    protected $id;
59
60
    public function __construct(IconFactory $iconFactory, UriBuilder $uriBuilder)
61
    {
62
        $this->iconFactory = $iconFactory;
63
        $this->uriBuilder = $uriBuilder;
64
    }
65
66
    /**
67
     * Init, called from parent object
68
     *
69
     * @param InfoModuleController $pObj A reference to the parent (calling) object
70
     */
71
    public function init(InfoModuleController $pObj, ServerRequestInterface $request)
72
    {
73
        $this->getLanguageService()->includeLLFile('EXT:info/Resources/Private/Language/InfoPageTsConfig.xlf');
74
        $this->view = $this->getFluidTemplateObject();
75
        $this->pObj = $pObj;
76
        $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
77
        // Setting MOD_MENU items as we need them for logging:
78
        $this->pObj->MOD_MENU = array_merge($this->pObj->MOD_MENU, $this->modMenu());
79
    }
80
81
    /**
82
     * Main, called from parent object
83
     *
84
     * @return string HTML output
85
     */
86
    public function main(ServerRequestInterface $request)
87
    {
88
        if ($this->id === 0) {
89
            $this->view->assign('pageZero', true);
90
            $pagesUsingTSConfig = $this->getOverviewOfPagesUsingTSConfig();
91
            if (count($pagesUsingTSConfig) > 0) {
92
                $this->view->assign('overviewOfPagesUsingTSConfig', $pagesUsingTSConfig);
93
            }
94
        } else {
95
            if ((int)$this->pObj->MOD_SETTINGS['tsconf_parts'] === 99) {
96
                $rootLine = BackendUtility::BEgetRootLine($this->id, '', true);
97
                /** @var array<string, string> $TSparts */
98
                $TSparts = GeneralUtility::makeInstance(PageTsConfigLoader::class)->collect($rootLine);
99
                $lines = [];
100
                $pUids = [];
101
102
                foreach ($TSparts as $k => $v) {
103
                    $line = [];
104
                    if ($k === 'default') {
105
                        $title = $this->getLanguageService()->sL('LLL:EXT:info/Resources/Private/Language/InfoPageTsConfig.xlf:editTSconfig_default');
106
                        $line['title'] = $title;
107
                    } else {
108
                        // Remove the "page_" prefix
109
                        [, $pageId] = explode('_', $k, 3);
110
                        $pageId = (int)$pageId;
111
                        $pUids[] = $pageId;
112
                        $row = BackendUtility::getRecordWSOL('pages', $pageId);
113
114
                        $icon = $this->iconFactory->getIconForRecord('pages', $row, Icon::SIZE_SMALL);
115
                        $urlParameters = [
116
                            'edit' => [
117
                                'pages' => [
118
                                    $pageId => 'edit',
119
                                ]
120
                            ],
121
                            'columnsOnly' => 'TSconfig,tsconfig_includes',
122
                            'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
123
                        ];
124
                        $line['editIcon'] = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
125
                        $line['editTitle'] = 'editTSconfig';
126
                        $title = BackendUtility::getRecordTitle('pages', $row);
127
                        $line['title'] = BackendUtility::wrapClickMenuOnIcon($icon, 'pages', $row['uid']) . ' ' . htmlspecialchars($title);
128
                    }
129
130
                    if (ExtensionManagementUtility::isLoaded('t3editor')) {
131
                        // @todo: Let EXT:t3editor add the deps via events in the render-loops above
132
                        $line['content'] = $this->getCodeMirrorHtml(
133
                            $title,
134
                            trim($v)
135
                        );
136
                        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
137
                        $pageRenderer->addCssFile('EXT:t3editor/Resources/Public/JavaScript/Contrib/codemirror/lib/codemirror.css');
138
                        $pageRenderer->addCssFile('EXT:t3editor/Resources/Public/Css/t3editor.css');
139
                        $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/Element/CodeMirrorElement');
140
                    } else {
141
                        $line['content'] = $this->getTextareaMarkup(trim($v));
142
                    }
143
144
                    $lines[] = $line;
145
                }
146
147
                if (!empty($pUids)) {
148
                    $urlParameters = [
149
                        'edit' => [
150
                            'pages' => [
151
                                implode(',', $pUids) => 'edit',
152
                            ]
153
                        ],
154
                        'columnsOnly' => 'TSconfig,tsconfig_includes',
155
                        'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri()
156
                    ];
157
                    $url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
158
                    $editIcon = htmlspecialchars($url);
159
                    $editTitle = 'editTSconfig_all';
160
                } else {
161
                    $editIcon = '';
162
                    $editTitle = '';
163
                }
164
165
                $this->view->assign('tsconfParts99', true);
166
                $this->view->assign('csh', BackendUtility::cshItem('_MOD_web_info', 'tsconfig_edit', '', '|'));
167
                $this->view->assign('lines', $lines);
168
                $this->view->assign('editIcon', $editIcon);
169
                $this->view->assign('editTitle', $editTitle);
170
            } else {
171
                $this->view->assign('tsconfParts99', false);
172
                // Defined global here!
173
                $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
174
                $tmpl->ext_expandAllNotes = 1;
175
                $tmpl->ext_noPMicons = 1;
176
177
                $pageTsConfig = BackendUtility::getPagesTSconfig($this->id);
178
                switch ($this->pObj->MOD_SETTINGS['tsconf_parts']) {
179
                    case '1':
180
                        $pageTsConfig = $pageTsConfig['mod.'] ?? [];
181
                        break;
182
                    case '1a':
183
                        $pageTsConfig = $pageTsConfig['mod.']['web_layout.'] ?? [];
184
                        break;
185
                    case '1b':
186
                        $pageTsConfig = $pageTsConfig['mod.']['web_view.'] ?? [];
187
                        break;
188
                    case '1c':
189
                        $pageTsConfig = $pageTsConfig['mod.']['web_modules.'] ?? [];
190
                        break;
191
                    case '1d':
192
                        $pageTsConfig = $pageTsConfig['mod.']['web_list.'] ?? [];
193
                        break;
194
                    case '1e':
195
                        $pageTsConfig = $pageTsConfig['mod.']['web_info.'] ?? [];
196
                        break;
197
                    case '1g':
198
                        $pageTsConfig = $pageTsConfig['mod.']['web_ts.'] ?? [];
199
                        break;
200
                    case '2':
201
                        $pageTsConfig = $pageTsConfig['RTE.'] ?? [];
202
                        break;
203
                    case '5':
204
                        $pageTsConfig = $pageTsConfig['TCEFORM.'] ?? [];
205
                        break;
206
                    case '6':
207
                        $pageTsConfig = $pageTsConfig['TCEMAIN.'] ?? [];
208
                        break;
209
                    case '7':
210
                        $pageTsConfig = $pageTsConfig['TCAdefaults.'] ?? [];
211
                        break;
212
                    case '4':
213
                        $pageTsConfig = $pageTsConfig['user.'] ?? [];
214
                        break;
215
                    default:
216
                        // Entire array
217
                }
218
219
                $this->view->assign('csh', BackendUtility::cshItem('_MOD_web_info', 'tsconfig_hierarchy', '', '|'));
220
                $this->view->assign('tree', $tmpl->ext_getObjTree($pageTsConfig, '', '', '', '', $this->pObj->MOD_SETTINGS['tsconf_alphaSort']));
221
            }
222
            $this->view->assign('alphaSort', BackendUtility::getFuncCheck($this->id, 'SET[tsconf_alphaSort]', $this->pObj->MOD_SETTINGS['tsconf_alphaSort'], '', '', 'id="checkTsconf_alphaSort"'));
223
            $this->view->assign('dropdownMenu', BackendUtility::getDropdownMenu($this->id, 'SET[tsconf_parts]', $this->pObj->MOD_SETTINGS['tsconf_parts'], $this->pObj->MOD_MENU['tsconf_parts']));
224
        }
225
        return $this->view->render();
226
    }
227
228
    /**
229
     * Function menu initialization
230
     *
231
     * @return array Menu array
232
     */
233
    protected function modMenu()
234
    {
235
        $lang = $this->getLanguageService();
236
        $modMenuAdd = [
237
            'tsconf_parts' => [
238
                0 => $lang->getLL('tsconf_parts_0'),
239
                1 => $lang->getLL('tsconf_parts_1'),
240
                '1a' => $lang->getLL('tsconf_parts_1a'),
241
                '1b' => $lang->getLL('tsconf_parts_1b'),
242
                '1c' => $lang->getLL('tsconf_parts_1c'),
243
                '1d' => $lang->getLL('tsconf_parts_1d'),
244
                '1e' => $lang->getLL('tsconf_parts_1e'),
245
                '1g' => $lang->getLL('tsconf_parts_1g'),
246
                2 => 'RTE.',
247
                7 => 'TCAdefaults.',
248
                5 => 'TCEFORM.',
249
                6 => 'TCEMAIN.',
250
                4 => 'user.',
251
                99 => $lang->getLL('tsconf_configFields')
252
            ],
253
            'tsconf_alphaSort' => '1'
254
        ];
255
        if (!$this->getBackendUser()->isAdmin()) {
256
            unset($modMenuAdd['tsconf_parts'][99]);
257
        }
258
        return $modMenuAdd;
259
    }
260
261
    /**
262
     * Renders table rows of all pages containing TSConfig together with its rootline
263
     *
264
     * @return array
265
     */
266
    protected function getOverviewOfPagesUsingTSConfig()
267
    {
268
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
269
        $queryBuilder->getRestrictions()
270
            ->removeAll()
271
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
272
            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, 0));
273
274
        $res = $queryBuilder
275
            ->select('uid', 'TSconfig')
276
            ->from('pages')
277
            ->where(
278
                $queryBuilder->expr()->neq(
279
                    'TSconfig',
280
                    $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
281
                )
282
            )
283
            ->execute();
284
285
        $pageArray = [];
286
287
        while ($row = $res->fetch()) {
288
            $this->setInPageArray($pageArray, BackendUtility::BEgetRootLine($row['uid'], 'AND 1=1'), $row);
289
        }
290
        return $this->getList($pageArray);
291
    }
292
293
    /**
294
     * Set page in array
295
     * This function is called recursively and builds a multi-dimensional array that reflects the page
296
     * hierarchy.
297
     *
298
     * @param array $hierarchicArray The hierarchic array (passed by reference)
299
     * @param array $rootlineArray The rootline array
300
     * @param array $row The row from the database containing the uid and TSConfig fields
301
     */
302
    protected function setInPageArray(&$hierarchicArray, $rootlineArray, $row)
303
    {
304
        ksort($rootlineArray);
305
        reset($rootlineArray);
306
        if (!$rootlineArray[0]['uid']) {
307
            array_shift($rootlineArray);
308
        }
309
        $currentElement = current($rootlineArray);
310
        $hierarchicArray[$currentElement['uid']] = htmlspecialchars($currentElement['title']);
311
        array_shift($rootlineArray);
312
        if (!empty($rootlineArray)) {
313
            if (!isset($hierarchicArray[$currentElement['uid'] . '.'])) {
314
                $hierarchicArray[$currentElement['uid'] . '.'] = [];
315
            }
316
            $this->setInPageArray($hierarchicArray[$currentElement['uid'] . '.'], $rootlineArray, $row);
317
        } else {
318
            $hierarchicArray[$currentElement['uid'] . '_'] = $this->extractLinesFromTSConfig($row);
319
        }
320
    }
321
322
    /**
323
     * Extract the lines of TSConfig from a given pages row
324
     *
325
     * @param array $row The row from the database containing the uid and TSConfig fields
326
     * @return array
327
     */
328
    protected function extractLinesFromTSConfig(array $row)
329
    {
330
        $out = [];
331
        $includeLines = 0;
332
        $out['uid'] = $row['uid'];
333
        $lines = GeneralUtility::trimExplode("\r\n", $row['TSconfig']);
334
        foreach ($lines as $line) {
335
            if (strpos($line, '<INCLUDE_TYPOSCRIPT:') !== false) {
336
                $includeLines++;
337
            }
338
        }
339
        $out['includeLines'] = $includeLines;
340
        $out['writtenLines'] = (count($lines) - $includeLines);
341
        return $out;
342
    }
343
344
    /**
345
     * Get the list of pages to show.
346
     * This function is called recursively
347
     *
348
     * @param array $pageArray The Page Array
349
     * @param array $lines Lines that have been processed up to this point
350
     * @param int $pageDepth The level of the current $pageArray being processed
351
     * @return array
352
     */
353
    protected function getList($pageArray, $lines = [], $pageDepth = 0)
354
    {
355
        if (!is_array($pageArray)) {
0 ignored issues
show
introduced by
The condition is_array($pageArray) is always true.
Loading history...
356
            return $lines;
357
        }
358
359
        foreach ($pageArray as $identifier => $_) {
360
            if (!MathUtility::canBeInterpretedAsInteger($identifier)) {
361
                continue;
362
            }
363
            $line = [];
364
            $line['padding'] = ($pageDepth * 20) + 10;
365
            if (isset($pageArray[$identifier . '_'])) {
366
                $line['link'] = GeneralUtility::linkThisScript(['id' => $identifier]);
367
                $line['icon'] = $this->iconFactory->getIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $identifier), Icon::SIZE_SMALL)->render();
368
                $line['title'] = 'ID: ' . $identifier;
369
                $line['pageTitle'] = GeneralUtility::fixed_lgd_cs($pageArray[$identifier], 30);
370
                $line['includedFiles'] = ($pageArray[$identifier . '_']['includeLines'] === 0 ? '' : $pageArray[$identifier . '_']['includeLines']);
371
                $line['lines'] = ($pageArray[$identifier . '_']['writtenLines'] === 0 ? '' : $pageArray[$identifier . '_']['writtenLines']);
372
            } else {
373
                $line['link'] = '';
374
                $line['icon'] = $this->iconFactory->getIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $identifier), Icon::SIZE_SMALL)->render();
375
                $line['title'] = '';
376
                $line['pageTitle'] = GeneralUtility::fixed_lgd_cs($pageArray[$identifier], 30);
377
                $line['includedFiles'] = '';
378
                $line['lines'] = '';
379
            }
380
            $lines[] = $line;
381
            $lines = $this->getList($pageArray[$identifier . '.'], $lines, $pageDepth + 1);
382
        }
383
        return $lines;
384
    }
385
386
    /**
387
     * returns a new standalone view, shorthand function
388
     *
389
     * @return StandaloneView
390
     */
391
    protected function getFluidTemplateObject()
392
    {
393
        $view = GeneralUtility::makeInstance(StandaloneView::class);
394
        $view->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:info/Resources/Private/Layouts')]);
395
        $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:info/Resources/Private/Partials')]);
396
        $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:info/Resources/Private/Templates')]);
397
398
        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:info/Resources/Private/Templates/PageTsConfig.html'));
399
400
        $view->getRequest()->setControllerExtensionName('info');
401
        return $view;
402
    }
403
404
    protected function getCodeMirrorHtml(string $label, string $content): string
405
    {
406
        $codeMirrorConfig = [
407
            'label' => $label,
408
            'panel' => 'top',
409
            'mode' => 'TYPO3/CMS/T3editor/Mode/typoscript/typoscript',
410
            'autoheight' => 'true',
411
            'nolazyload' => 'true',
412
            'options' => GeneralUtility::jsonEncodeForHtmlAttribute([
413
                'readOnly' => true,
414
                'format' => 'typoscript',
415
                'rows' => 'auto',
416
            ], false),
417
        ];
418
        $textareaAttributes = [
419
            'rows' => (string)count(explode(LF, $content)),
420
            'readonly' => 'readonly',
421
        ];
422
423
        $code = '<typo3-t3editor-codemirror ' . GeneralUtility::implodeAttributes($codeMirrorConfig, true) . '>';
424
        $code .= '<textarea ' . GeneralUtility::implodeAttributes($textareaAttributes, true) . '>' . htmlspecialchars($content) . '</textarea>';
425
        $code .= '</typo3-t3editor-codemirror>';
426
427
        return $code;
428
    }
429
430
    protected function getTextareaMarkup(string $content): string
431
    {
432
        return '<textarea class="form-control" rows="' . (string)count(explode(LF, $content)) . '" disabled>'
433
            . htmlspecialchars($content)
434
            . '</textarea>';
435
    }
436
437
    /**
438
     * @return BackendUserAuthentication
439
     */
440
    protected function getBackendUser(): BackendUserAuthentication
441
    {
442
        return $GLOBALS['BE_USER'];
443
    }
444
445
    /**
446
     * @return LanguageService
447
     */
448
    protected function getLanguageService(): LanguageService
449
    {
450
        return $GLOBALS['LANG'];
451
    }
452
}
453