Passed
Push — refactor/backendModule-ValueOb... ( 7f4b86...3e8499 )
by Tomas Norre
07:27
created

LogRequestForm   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 374
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 203
c 4
b 0
f 0
dl 0
loc 374
ccs 0
cts 256
cp 0
rs 8.72
wmc 46

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getDisplayLogFilterHtml() 0 9 1
A getShowFeVarsCheckBoxHtml() 0 9 1
A getIconFactory() 0 3 1
A outputCsvFile() 0 14 2
A getDepthDropDownHtml() 0 7 1
A getShowResultLogCheckBoxHtml() 0 9 1
D drawLog_addRows() 0 93 23
A __construct() 0 8 1
A render() 0 8 2
C showLogAction() 0 120 12
A getItemsPerPageDropDownHtml() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like LogRequestForm 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 LogRequestForm, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace AOE\Crawler\Backend\RequestForm;
6
7
use AOE\Crawler\Backend\Helper\ResultHandler;
8
use AOE\Crawler\Backend\Helper\UrlBuilder;
9
use AOE\Crawler\Converter\JsonCompatibilityConverter;
10
use AOE\Crawler\Utility\MessageUtility;
11
use AOE\Crawler\Writer\FileWriter\CsvWriter\CrawlerCsvWriter;
12
use AOE\Crawler\Writer\FileWriter\CsvWriter\CsvWriterInterface;
13
use Doctrine\DBAL\Query\QueryBuilder;
14
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
15
use TYPO3\CMS\Backend\Utility\BackendUtility;
16
use TYPO3\CMS\Core\Database\ConnectionPool;
17
use TYPO3\CMS\Core\Imaging\Icon;
18
use TYPO3\CMS\Core\Imaging\IconFactory;
19
use TYPO3\CMS\Core\Utility\DebugUtility;
20
use TYPO3\CMS\Core\Utility\GeneralUtility;
21
use TYPO3\CMS\Fluid\View\StandaloneView;
22
use TYPO3\CMS\Info\Controller\InfoModuleController;
23
24
final class LogRequestForm extends AbstractRequestForm implements RequestFormInterface
25
{
26
    /**
27
     * @var StandaloneView
28
     */
29
    private $view;
30
31
    /**
32
     * @var JsonCompatibilityConverter
33
     */
34
    private $jsonCompatibilityConverter;
35
36
    /**
37
     * @var int
38
     */
39
    private $pageId;
40
41
    /**
42
     * @var bool
43
     */
44
    private $CSVExport = false;
45
46
    /**
47
     * @var InfoModuleController
48
     */
49
    private $infoModuleController;
50
51
    /**
52
     * @var QueryBuilder
53
     */
54
    private $queryBuilder;
55
56
    /**
57
     * @var CsvWriterInterface
58
     */
59
    private $csvWriter;
60
61
    /**
62
     * @var array
63
     */
64
    private $CSVaccu = [];
65
66
    public function __construct(StandaloneView $view, InfoModuleController $infoModuleController, array $extensionSettings)
67
    {
68
        $this->view = $view;
69
        $this->infoModuleController = $infoModuleController;
70
        $this->jsonCompatibilityConverter = new JsonCompatibilityConverter();
71
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_crawler_queue');
72
        $this->csvWriter = new CrawlerCsvWriter();
73
        $this->extensionSettings = $extensionSettings;
74
    }
75
76
    public function render($id, string $currentValue, array $menuItems): string
77
    {
78
        $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . (int) GeneralUtility::_GP('qid_details') : '';
79
        $setId = (int) GeneralUtility::_GP('setID');
80
        $this->pageId = $id;
81
82
        return $this->getDepthDropDownHtml($id, $currentValue, $menuItems)
83
            . $this->showLogAction($setId, $quiPart);
84
    }
85
86
    private function getDepthDropDownHtml($id, string $currentValue, array $menuItems): string
87
    {
88
        return BackendUtility::getFuncMenu(
89
            $id,
90
            'SET[depth]',
91
            $currentValue,
92
            $menuItems
93
        );
94
    }
95
96
    /*******************************
97
     *
98
     * Shows log of indexed URLs
99
     *
100
     ******************************/
101
102
    /**
103
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
104
     */
105
    private function showLogAction(int $setId, string $quiPath): string
106
    {
107
        $this->view->setTemplate('ShowLog');
108
        if (empty($this->pageId)) {
109
            $this->isErrorDetected = true;
110
            MessageUtility::addErrorMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noPageSelected'));
111
        } else {
112
            $this->findCrawler()->setAccessMode('gui');
113
            $this->findCrawler()->setID = GeneralUtility::md5int(microtime());
114
115
            $csvExport = GeneralUtility::_POST('_csv');
116
            $this->CSVExport = isset($csvExport);
117
118
            // Read URL:
119
            if (GeneralUtility::_GP('qid_read')) {
120
                $this->findCrawler()->readUrl((int) GeneralUtility::_GP('qid_read'), true);
121
            }
122
123
            // Look for set ID sent - if it is, we will display contents of that set:
124
            $showSetId = (int) GeneralUtility::_GP('setID');
125
126
            $queueId = GeneralUtility::_GP('qid_details');
127
            $this->view->assign('queueId', $queueId);
128
            $this->view->assign('setId', $showSetId);
129
            // Show details:
130
            if ($queueId) {
131
                // Get entry record:
132
                $q_entry = $this->queryBuilder
133
                    ->from('tx_crawler_queue')
134
                    ->select('*')
135
                    ->where(
136
                        $this->queryBuilder->expr()->eq('qid', $this->queryBuilder->createNamedParameter($queueId))
137
                    )
138
                    ->execute()
139
                    ->fetch();
140
141
                // Explode values
142
                $q_entry['parameters'] = $this->jsonCompatibilityConverter->convert($q_entry['parameters']);
143
                $q_entry['result_data'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']);
144
                $resStatus = ResultHandler::getResStatus($q_entry['result_data']);
145
                if (is_array($q_entry['result_data'])) {
146
                    $q_entry['result_data']['content'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']['content']);
147
                    if (! $this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
148
                        unset($q_entry['result_data']['content']['log']);
149
                    }
150
                }
151
152
                $this->view->assign('queueStatus', $resStatus);
153
                $this->view->assign('queueDetails', DebugUtility::viewArray($q_entry));
154
            } else {
155
                // Show list
156
                // Drawing tree:
157
                $tree = GeneralUtility::makeInstance(PageTreeView::class);
158
                $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
159
                $tree->init('AND ' . $perms_clause);
160
161
                // Set root row:
162
                $pageinfo = BackendUtility::readPageAccess(
163
                    $this->pageId,
164
                    $perms_clause
165
                );
166
                $HTML = $this->getIconFactory()->getIconForRecord('pages', $pageinfo, Icon::SIZE_SMALL)->render();
167
                $tree->tree[] = [
168
                    'row' => $pageinfo,
169
                    'HTML' => $HTML,
170
                ];
171
172
                // Get branch beneath:
173
                if ($this->infoModuleController->MOD_SETTINGS['depth']) {
174
                    $tree->getTree($this->pageId, $this->infoModuleController->MOD_SETTINGS['depth']);
175
                }
176
177
                // If Flush button is pressed, flush tables instead of selecting entries:
178
                if (GeneralUtility::_POST('_flush')) {
179
                    $doFlush = true;
180
                    $doFullFlush = false;
181
                } elseif (GeneralUtility::_POST('_flush_all')) {
182
                    $doFlush = true;
183
                    $doFullFlush = true;
184
                } else {
185
                    $doFlush = false;
186
                    $doFullFlush = false;
187
                }
188
                $itemsPerPage = (int) $this->infoModuleController->MOD_SETTINGS['itemsPerPage'];
189
                // Traverse page tree:
190
                $code = '';
191
                $count = 0;
192
                foreach ($tree->tree as $data) {
193
                    // Get result:
194
                    $logEntriesOfPage = $this->crawlerController->getLogEntriesForPageId(
195
                        (int) $data['row']['uid'],
196
                        $this->infoModuleController->MOD_SETTINGS['log_display'],
197
                        $doFlush,
198
                        $doFullFlush,
199
                        $itemsPerPage
200
                    );
201
202
                    $code .= $this->drawLog_addRows(
203
                        $logEntriesOfPage,
204
                        $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true)
205
                    );
206
                    if (++$count === 1000) {
207
                        break;
208
                    }
209
                }
210
                $this->view->assign('code', $code);
211
            }
212
213
            if ($this->CSVExport) {
214
                $this->outputCsvFile();
215
            }
216
        }
217
        $this->view->assign('showResultLog', (bool) $this->infoModuleController->MOD_SETTINGS['log_resultLog']);
218
        $this->view->assign('showFeVars', (bool) $this->infoModuleController->MOD_SETTINGS['log_feVars']);
219
        $this->view->assign('displayActions', 1);
220
        $this->view->assign('displayLogFilterHtml', $this->getDisplayLogFilterHtml($setId));
221
        $this->view->assign('itemPerPageHtml', $this->getItemsPerPageDropDownHtml());
222
        $this->view->assign('showResultLogHtml', $this->getShowResultLogCheckBoxHtml($setId, $quiPath));
223
        $this->view->assign('showFeVarsHtml', $this->getShowFeVarsCheckBoxHtml($setId, $quiPath));
224
        return $this->view->render();
225
    }
226
227
    /**
228
     * Outputs the CSV file and sets the correct headers
229
     */
230
    private function outputCsvFile(): void
231
    {
232
        if (! count($this->CSVaccu)) {
233
            MessageUtility::addWarningMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:message.canNotExportEmptyQueueToCsvText'));
234
            return;
235
        }
236
237
        $csvString = $this->csvWriter->arrayToCsv($this->CSVaccu);
238
239
        header('Content-Type: application/octet-stream');
240
        header('Content-Disposition: attachment; filename=CrawlerLog.csv');
241
        echo $csvString;
242
243
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
244
    }
245
246
    private function getIconFactory(): IconFactory
247
    {
248
        return GeneralUtility::makeInstance(IconFactory::class);
249
    }
250
251
    private function getDisplayLogFilterHtml(int $setId): string
252
    {
253
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.display') . ': ' . BackendUtility::getFuncMenu(
254
                $this->pageId,
255
                'SET[log_display]',
256
                $this->infoModuleController->MOD_SETTINGS['log_display'],
257
                $this->infoModuleController->MOD_MENU['log_display'],
258
                'index.php',
259
                '&setID=' . $setId
260
            );
261
    }
262
263
    private function getItemsPerPageDropDownHtml(): string
264
    {
265
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.itemsPerPage') . ': ' .
266
            BackendUtility::getFuncMenu(
267
                $this->pageId,
268
                'SET[itemsPerPage]',
269
                $this->infoModuleController->MOD_SETTINGS['itemsPerPage'],
270
                $this->infoModuleController->MOD_MENU['itemsPerPage']
271
            );
272
    }
273
274
    private function getShowResultLogCheckBoxHtml(int $setId, string $quiPart): string
275
    {
276
        return BackendUtility::getFuncCheck(
277
                $this->pageId,
278
                'SET[log_resultLog]',
279
                $this->infoModuleController->MOD_SETTINGS['log_resultLog'],
280
                'index.php',
281
                '&setID=' . $setId . $quiPart
282
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showresultlog');
283
    }
284
285
    private function getShowFeVarsCheckBoxHtml(int $setId, string $quiPart): string
286
    {
287
        return BackendUtility::getFuncCheck(
288
                $this->pageId,
289
                'SET[log_feVars]',
290
                $this->infoModuleController->MOD_SETTINGS['log_feVars'],
291
                'index.php',
292
                '&setID=' . $setId . $quiPart
293
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showfevars');
294
    }
295
296
    /**
297
     * Create the rows for display of the page tree
298
     * For each page a number of rows are shown displaying GET variable configuration
299
     *
300
     * @param array $logEntriesOfPage Log items of one page
301
     * @param string $titleString Title string
302
     * @return string HTML <tr> content (one or more)
303
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
304
     */
305
    private function drawLog_addRows(array $logEntriesOfPage, string $titleString): string
306
    {
307
        $colSpan = 9
308
            + ($this->infoModuleController->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
309
            + ($this->infoModuleController->MOD_SETTINGS['log_feVars'] ? 3 : 0);
310
311
        if (! empty($logEntriesOfPage)) {
312
            $setId = (int) GeneralUtility::_GP('setID');
313
            $refreshIcon = $this->getIconFactory()->getIcon('actions-system-refresh', Icon::SIZE_SMALL);
314
            // Traverse parameter combinations:
315
            $c = 0;
316
            $content = '';
317
            foreach ($logEntriesOfPage as $vv) {
318
                // Title column:
319
                if (! $c) {
320
                    $titleClm = '<td rowspan="' . count($logEntriesOfPage) . '">' . $titleString . '</td>';
321
                } else {
322
                    $titleClm = '';
323
                }
324
325
                // Result:
326
                $resLog = ResultHandler::getResultLog($vv);
327
328
                $resultData = $vv['result_data'] ? $this->jsonCompatibilityConverter->convert($vv['result_data']) : [];
329
                $resStatus = ResultHandler::getResStatus($resultData);
330
331
                // Compile row:
332
                $parameters = $this->jsonCompatibilityConverter->convert($vv['parameters']);
333
334
                // Put data into array:
335
                $rowData = [];
336
                if ($this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
337
                    $rowData['result_log'] = $resLog;
338
                } else {
339
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.immediate');
340
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
341
                }
342
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
343
                $url = htmlspecialchars($parameters['url'] ?? $parameters['alturl'], ENT_QUOTES | ENT_HTML5);
344
                $rowData['url'] = '<a href="' . $url . '" target="_newWIndow">' . $url . '</a>';
345
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'] ?: '';
346
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
347
                $rowData['set_id'] = (string) $vv['set_id'];
348
349
                if ($this->infoModuleController->MOD_SETTINGS['log_feVars']) {
350
                    $resFeVars = ResultHandler::getResFeVars($resultData ?: []);
0 ignored issues
show
Bug introduced by
It seems like $resultData ?: array() can also be of type true; however, parameter $resultData of AOE\Crawler\Backend\Help...Handler::getResFeVars() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

350
                    $resFeVars = ResultHandler::getResFeVars(/** @scrutinizer ignore-type */ $resultData ?: []);
Loading history...
351
                    $rowData['tsfe_id'] = $resFeVars['id'] ?: '';
352
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'] ?: '';
353
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'] ?: '';
354
                }
355
356
                $trClass = '';
357
                $warningIcon = '';
358
                if ($rowData['exec_time'] !== 0 && $resultData === false) {
359
                    $trClass = 'class="bg-danger"';
360
                    $warningIcon = $this->getIconFactory()->getIcon('actions-ban', Icon::SIZE_SMALL);
361
                }
362
363
                // Put rows together:
364
                $content .= '
365
                    <tr ' . $trClass . ' >
366
                        ' . $titleClm . '
367
                        <td><a href="' . UrlBuilder::getInfoModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars((string) $vv['qid']) . '</a></td>
368
                        <td><a href="' . UrlBuilder::getInfoModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]) . '">' . $refreshIcon . '</a>&nbsp;&nbsp;' . $warningIcon . '</td>';
369
                foreach ($rowData as $fKey => $value) {
370
                    if ($fKey === 'url') {
371
                        $content .= '<td>' . $value . '</td>';
372
                    } else {
373
                        $content .= '<td>' . nl2br(htmlspecialchars(strval($value))) . '</td>';
374
                    }
375
                }
376
                $content .= '</tr>';
377
                $c++;
378
379
                if ($this->CSVExport) {
380
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
381
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
382
                    $rowData['qid'] = $vv['qid'];
383
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
384
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
385
                    $this->CSVaccu[] = $rowData;
386
                }
387
            }
388
        } else {
389
            // Compile row:
390
            $content = '
391
                <tr>
392
                    <td>' . $titleString . '</td>
393
                    <td colspan="' . $colSpan . '"><em>' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noentries') . '</em></td>
394
                </tr>';
395
        }
396
397
        return $content;
398
    }
399
}
400