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

TemplateAnalyzerModuleFunctionController::main()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 54
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 32
c 0
b 0
f 0
dl 0
loc 54
rs 9.408
cc 4
nc 8
nop 0

How to fix   Long Method   

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\Tstemplate\Controller;
17
18
use Psr\Http\Message\ServerRequestInterface;
19
use TYPO3\CMS\Core\Page\PageRenderer;
20
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
21
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Core\Utility\RootlineUtility;
24
use TYPO3\CMS\Fluid\View\StandaloneView;
25
26
/**
27
 * TypoScript template analyzer
28
 * @internal This is a specific Backend Controller implementation and is not considered part of the Public TYPO3 API.
29
 */
30
class TemplateAnalyzerModuleFunctionController
31
{
32
33
    /**
34
     * @var TypoScriptTemplateModuleController
35
     */
36
    protected $pObj;
37
38
    /**
39
     * The currently selected sys_template record
40
     * @var array|null
41
     */
42
    protected $templateRow;
43
44
    /**
45
     * @var ExtendedTemplateService
46
     */
47
    protected $templateService;
48
49
    /**
50
     * @var ServerRequestInterface
51
     */
52
    protected $request;
53
54
    /**
55
     * Init, called from parent object
56
     *
57
     * @param TypoScriptTemplateModuleController $pObj
58
     * @param ServerRequestInterface $request
59
     */
60
    public function init($pObj, ServerRequestInterface $request)
61
    {
62
        $this->pObj = $pObj;
63
        $this->request = $request;
64
    }
65
66
    /**
67
     * Main, called from parent object
68
     *
69
     * @return string
70
     */
71
    public function main()
72
    {
73
        // The page id TypoScript tree should be show for
74
        $pageUid = (int)($this->request->getParsedBody()['id'] ?? $this->request->getQueryParams()['id'] ?? 0);
75
        // Set if user clicked on one template to show content of this specific one
76
        $selectedTemplate = ($this->request->getQueryParams()['template'] ?? '');
77
        // The template object browser shows info boxes with parser errors and links to template analyzer to highlight
78
        // affected line. Increased by one if set to avoid an off-by-one error.
79
        $highlightLine = (int)($this->request->getQueryParams()['highlightLine'] ?? 0);
80
        // 'const' or 'setup' or not set
81
        $highlightType = (string)($this->request->getQueryParams()['highlightType'] ?? '');
82
83
        $assigns = [
84
            'pageUid' => $pageUid,
85
        ];
86
87
        $templateUid = 0;
88
        $assigns['manyTemplatesMenu'] = $this->pObj->templateMenu($this->request);
89
        if ($assigns['manyTemplatesMenu']) {
90
            $templateUid = (int)$this->pObj->MOD_SETTINGS['templatesOnPage'];
91
        }
92
93
        $assigns['existTemplate'] = $this->initializeTemplates($pageUid, $templateUid);
94
        if ($assigns['existTemplate']) {
95
            $assigns['templateRecord'] = $this->templateRow;
96
            $assigns['linkWrappedTemplateTitle'] = $this->pObj->linkWrapTemplateTitle($this->templateRow['title']);
97
        }
98
99
        $this->templateService->clearList_const_temp = array_flip($this->templateService->clearList_const);
100
        $this->templateService->clearList_setup_temp = array_flip($this->templateService->clearList_setup);
101
        $pointer = count($this->templateService->hierarchyInfo);
102
        $hierarchyInfo = $this->templateService->ext_process_hierarchyInfo([], $pointer);
103
        $assigns['hierarchy'] = implode('', array_reverse($this->templateService->ext_getTemplateHierarchyArr(
104
            $hierarchyInfo,
105
            '',
106
            [],
107
            1
108
        )));
109
110
        $assigns['constants'] =  $this->renderTemplates($this->templateService->constants, $selectedTemplate, $highlightType === 'const', $highlightLine);
111
        $assigns['setups'] =  $this->renderTemplates($this->templateService->config, $selectedTemplate, $highlightType === 'setup', $highlightLine);
112
113
        if (ExtensionManagementUtility::isLoaded('t3editor')) {
114
            // @todo: Let EXT:t3editor add the deps via events in the render-loops above
115
            $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
116
            $pageRenderer->addCssFile('EXT:t3editor/Resources/Public/JavaScript/Contrib/codemirror/lib/codemirror.css');
117
            $pageRenderer->addCssFile('EXT:t3editor/Resources/Public/Css/t3editor.css');
118
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/Element/CodeMirrorElement');
119
        }
120
121
        $view = GeneralUtility::makeInstance(StandaloneView::class);
122
        $view->setTemplatePathAndFilename('EXT:tstemplate/Resources/Private/Templates/TemplateAnalyzerModuleFunction.html');
123
        $view->assignMultiple($assigns);
124
        return $view->render();
125
    }
126
127
    protected function initializeTemplates(int $pageId, int $templateUid = 0): bool
128
    {
129
        // Initializes the module. Done in this function because we may need to re-initialize if data is submitted!
130
        $this->templateService = GeneralUtility::makeInstance(ExtendedTemplateService::class);
131
132
        // Gets the rootLine
133
        $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $pageId);
134
        $rootLine = $rootlineUtility->get();
135
136
        // This generates the constants/config + hierarchy info for the template.
137
        $this->templateService->runThroughTemplates($rootLine, $templateUid);
138
139
        // Get the row of the first VISIBLE template of the page. where clause like the frontend.
140
        $this->templateRow = $this->templateService->ext_getFirstTemplate($pageId, $templateUid);
141
        return is_array($this->templateRow);
142
    }
143
144
    /**
145
     * Render constants or setup templates using t3editor or plain textarea
146
     *
147
     * @param array $templates
148
     * @param string $selectedTemplate
149
     * @param bool $highlight
150
     * @param int $highlightLine
151
     * @return array Modified assign array
152
     */
153
    protected function renderTemplates(array $templates, string $selectedTemplate, bool $highlight, int $highlightLine): array
154
    {
155
        $templatesMarkup = [];
156
        $totalLines = 0;
157
        foreach ($templates as $templateNumber => $templateContent) {
158
            $totalLines += 1 + count(explode(LF, $templateContent));
159
        }
160
        $thisLineOffset = $nextLineOffset = 0;
161
        foreach ($templates as $templateNumber => $templateContent) {
162
            $templateId = $this->templateService->hierarchyInfo[$templateNumber]['templateID'];
163
            $templateTitle = $this->templateService->hierarchyInfo[$templateNumber]['title'] ?? 'Template';
164
            // Prefix content with '[GLOBAL]' even for empty strings, the TemplateService does that, too.
165
            // Not replicating this leads to shifted line numbers when parser errors are reported in FE and object browser.
166
            // @todo: Locate where TemplateService hard prefixes this for empty strings and drop it.
167
            $templateContent = '[GLOBAL]' . LF . (string)$templateContent;
168
            $linesInTemplate = count(explode(LF, $templateContent));
169
            $nextLineOffset += $linesInTemplate;
170
            if ($selectedTemplate === 'all'
171
                || $templateId === $selectedTemplate
172
                || $highlight && $highlightLine && $highlightLine > $thisLineOffset && $highlightLine <= $nextLineOffset
173
            ) {
174
                if (ExtensionManagementUtility::isLoaded('t3editor')) {
175
                    // @todo: Fire event and let EXT:t3editor fill the markup
176
                    $templatesMarkup[] = $this->getCodeMirrorMarkup(
177
                        $templateTitle,
178
                        $thisLineOffset,
179
                        $linesInTemplate,
180
                        $totalLines,
181
                        $highlight ? $highlightLine : 0,
182
                        $templateContent
183
                    );
184
                } else {
185
                    $templatesMarkup[] = $this->getTextareaMarkup(
186
                        $templateTitle,
187
                        $linesInTemplate,
188
                        $templateContent
189
                    );
190
                }
191
            }
192
            $thisLineOffset = $nextLineOffset;
193
        }
194
        return $templatesMarkup;
195
    }
196
197
    protected function getCodeMirrorMarkup(
198
        string $label,
199
        int $lineOffset,
200
        int $lines,
201
        int $totalLines,
202
        int $highlightLine,
203
        string $content
204
    ): string {
205
        $codeMirrorConfig = [
206
            'label' => $label,
207
            'panel' => 'top',
208
            'mode' => 'TYPO3/CMS/T3editor/Mode/typoscript/typoscript',
209
            'autoheight' => 'true',
210
            'nolazyload' => 'true',
211
            'linedigits' => (string)strlen((string)$totalLines),
212
            'options' => GeneralUtility::jsonEncodeForHtmlAttribute([
213
                'readOnly' => true,
214
                'format' => 'typoscript',
215
                'rows' => 'auto',
216
                'firstLineNumber' => $lineOffset + 1,
217
            ], false),
218
        ];
219
        $textareaAttributes = [
220
            'rows' => (string)$lines,
221
            'readonly' => 'readonly',
222
        ];
223
224
        // If we want to highlight
225
        if ($highlightLine && $highlightLine >= $lineOffset && $highlightLine <= ($lineOffset + $lines)) {
226
            // Scroll to affected line and highlight line if requested
227
            $targetLineInTemplate = $highlightLine - $lineOffset;
228
            $codeMirrorConfig['scrollto'] = (string)$targetLineInTemplate;
229
            $codeMirrorConfig['marktext'] = GeneralUtility::jsonEncodeForHtmlAttribute([
230
                [
231
                    'from' => [
232
                        'line' => $targetLineInTemplate - 1,
233
                        'ch' => 0,
234
                    ],
235
                    'to' => [
236
                        'line' => $targetLineInTemplate - 1,
237
                        // Arbitrary high value to match full line
238
                        'ch' => 10000,
239
                    ]
240
                ]
241
            ], false);
242
        }
243
244
        $code = '<typo3-t3editor-codemirror ' . GeneralUtility::implodeAttributes($codeMirrorConfig, true) . '>';
245
        $code .= '<textarea ' . GeneralUtility::implodeAttributes($textareaAttributes, true) . '>' . htmlspecialchars($content) . '</textarea>';
246
        $code .= '</typo3-t3editor-codemirror>';
247
248
        return $code;
249
    }
250
251
    protected function getTextareaMarkup(string $title, int $linesInTemplate, string $content): string
252
    {
253
        return htmlspecialchars($title)
254
            . '<textarea class="form-control" rows="' . ($linesInTemplate + 1) . '" disabled>'
255
            . htmlspecialchars($content)
256
            . '</textarea>';
257
    }
258
}
259