Passed
Push — github-actions ( 1bf7ac...aaecb2 )
by Tomas Norre
14:09
created

LogRequestForm::drawLog_addRows()   D

Complexity

Conditions 22
Paths 8

Size

Total Lines 93
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 22
eloc 62
c 1
b 0
f 0
nc 8
nop 2
dl 0
loc 93
rs 4.1666

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
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\Value\QueueFilter;
12
use AOE\Crawler\Writer\FileWriter\CsvWriter\CrawlerCsvWriter;
13
use AOE\Crawler\Writer\FileWriter\CsvWriter\CsvWriterInterface;
14
use Doctrine\DBAL\Query\QueryBuilder;
15
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
16
use TYPO3\CMS\Backend\Utility\BackendUtility;
17
use TYPO3\CMS\Core\Database\ConnectionPool;
18
use TYPO3\CMS\Core\Imaging\Icon;
19
use TYPO3\CMS\Core\Imaging\IconFactory;
20
use TYPO3\CMS\Core\Utility\DebugUtility;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
use TYPO3\CMS\Fluid\View\StandaloneView;
23
use TYPO3\CMS\Info\Controller\InfoModuleController;
24
25
final class LogRequestForm extends AbstractRequestForm implements RequestFormInterface
26
{
27
    /**
28
     * @var StandaloneView
29
     */
30
    private $view;
31
32
    /**
33
     * @var JsonCompatibilityConverter
34
     */
35
    private $jsonCompatibilityConverter;
36
37
    /**
38
     * @var int
39
     */
40
    private $pageId;
41
42
    /**
43
     * @var bool
44
     */
45
    private $CSVExport = false;
46
47
    /**
48
     * @var InfoModuleController
49
     */
50
    private $infoModuleController;
51
52
    /**
53
     * @var QueryBuilder
54
     */
55
    private $queryBuilder;
56
57
    /**
58
     * @var CsvWriterInterface
59
     */
60
    private $csvWriter;
61
62
    /**
63
     * @var array
64
     */
65
    private $CSVaccu = [];
66
67
    public function __construct(StandaloneView $view, InfoModuleController $infoModuleController, array $extensionSettings)
68
    {
69
        $this->view = $view;
70
        $this->infoModuleController = $infoModuleController;
71
        $this->jsonCompatibilityConverter = new JsonCompatibilityConverter();
72
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_crawler_queue');
73
        $this->csvWriter = new CrawlerCsvWriter();
74
        $this->extensionSettings = $extensionSettings;
75
    }
76
77
    public function render($id, string $currentValue, array $menuItems): string
78
    {
79
        $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . (int) GeneralUtility::_GP('qid_details') : '';
80
        $setId = (int) GeneralUtility::_GP('setID');
81
        $this->pageId = $id;
82
83
        return $this->getDepthDropDownHtml($id, $currentValue, $menuItems)
84
            . $this->showLogAction($setId, $quiPart);
85
    }
86
87
    private function getDepthDropDownHtml($id, string $currentValue, array $menuItems): string
88
    {
89
        return BackendUtility::getFuncMenu(
90
            $id,
91
            'SET[depth]',
92
            $currentValue,
93
            $menuItems
94
        );
95
    }
96
97
    /*******************************
98
     *
99
     * Shows log of indexed URLs
100
     *
101
     ******************************/
102
103
    /**
104
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
105
     */
106
    private function showLogAction(int $setId, string $quiPath): string
107
    {
108
        $this->view->setTemplate('ShowLog');
109
        if (empty($this->pageId)) {
110
            $this->isErrorDetected = true;
111
            MessageUtility::addErrorMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noPageSelected'));
112
        } else {
113
            $this->findCrawler()->setAccessMode('gui');
0 ignored issues
show
Deprecated Code introduced by
The function AOE\Crawler\Controller\C...roller::setAccessMode() has been deprecated. ( Ignorable by Annotation )

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

113
            /** @scrutinizer ignore-deprecated */ $this->findCrawler()->setAccessMode('gui');
Loading history...
114
            $this->findCrawler()->setID = GeneralUtility::md5int(microtime());
115
116
            $csvExport = GeneralUtility::_POST('_csv');
117
            $this->CSVExport = isset($csvExport);
118
119
            // Read URL:
120
            if (GeneralUtility::_GP('qid_read')) {
121
                $this->findCrawler()->readUrl((int) GeneralUtility::_GP('qid_read'), true);
122
            }
123
124
            // Look for set ID sent - if it is, we will display contents of that set:
125
            $showSetId = (int) GeneralUtility::_GP('setID');
126
127
            $queueId = GeneralUtility::_GP('qid_details');
128
            $this->view->assign('queueId', $queueId);
129
            $this->view->assign('setId', $showSetId);
130
            // Show details:
131
            if ($queueId) {
132
                // Get entry record:
133
                $q_entry = $this->queryBuilder
134
                    ->from('tx_crawler_queue')
135
                    ->select('*')
136
                    ->where(
137
                        $this->queryBuilder->expr()->eq('qid', $this->queryBuilder->createNamedParameter($queueId))
138
                    )
139
                    ->execute()
140
                    ->fetch();
141
142
                // Explode values
143
                $q_entry['parameters'] = $this->jsonCompatibilityConverter->convert($q_entry['parameters']);
144
                $q_entry['result_data'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']);
145
                $resStatus = ResultHandler::getResStatus($q_entry['result_data']);
146
                if (is_array($q_entry['result_data'])) {
147
                    $q_entry['result_data']['content'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']['content']);
148
                    if (! $this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
149
                        unset($q_entry['result_data']['content']['log']);
150
                    }
151
                }
152
153
                $this->view->assign('queueStatus', $resStatus);
154
                $this->view->assign('queueDetails', DebugUtility::viewArray($q_entry));
155
            } else {
156
                // Show list
157
                // Drawing tree:
158
                $tree = GeneralUtility::makeInstance(PageTreeView::class);
159
                $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
160
                $tree->init('AND ' . $perms_clause);
161
162
                // Set root row:
163
                $pageinfo = BackendUtility::readPageAccess(
164
                    $this->pageId,
165
                    $perms_clause
166
                );
167
                $HTML = $this->getIconFactory()->getIconForRecord('pages', $pageinfo, Icon::SIZE_SMALL)->render();
168
                $tree->tree[] = [
169
                    'row' => $pageinfo,
170
                    'HTML' => $HTML,
171
                ];
172
173
                // Get branch beneath:
174
                if ($this->infoModuleController->MOD_SETTINGS['depth']) {
175
                    $tree->getTree($this->pageId, $this->infoModuleController->MOD_SETTINGS['depth']);
176
                }
177
178
                // If Flush button is pressed, flush tables instead of selecting entries:
179
                if (GeneralUtility::_POST('_flush')) {
180
                    $doFlush = true;
181
                    $doFullFlush = false;
182
                } elseif (GeneralUtility::_POST('_flush_all')) {
183
                    $doFlush = true;
184
                    $doFullFlush = true;
185
                } else {
186
                    $doFlush = false;
187
                    $doFullFlush = false;
188
                }
189
                $itemsPerPage = (int) $this->infoModuleController->MOD_SETTINGS['itemsPerPage'];
190
                $queueFilter = new QueueFilter($this->infoModuleController->MOD_SETTINGS['log_display']);
191
                // Traverse page tree:
192
                $code = '';
193
                $count = 0;
194
                foreach ($tree->tree as $data) {
195
                    // Get result:
196
                    $logEntriesOfPage = $this->crawlerController->getLogEntriesForPageId(
197
                        (int) $data['row']['uid'],
198
                        $queueFilter,
199
                        $doFlush,
200
                        $doFullFlush,
201
                        $itemsPerPage
202
                    );
203
204
                    $code .= $this->drawLog_addRows(
205
                        $logEntriesOfPage,
206
                        $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true)
207
                    );
208
                    if (++$count === 1000) {
209
                        break;
210
                    }
211
                }
212
                $this->view->assign('code', $code);
213
            }
214
215
            if ($this->CSVExport) {
216
                $this->outputCsvFile();
217
            }
218
        }
219
        $this->view->assign('showResultLog', (bool) $this->infoModuleController->MOD_SETTINGS['log_resultLog']);
220
        $this->view->assign('showFeVars', (bool) $this->infoModuleController->MOD_SETTINGS['log_feVars']);
221
        $this->view->assign('displayActions', 1);
222
        $this->view->assign('displayLogFilterHtml', $this->getDisplayLogFilterHtml($setId));
223
        $this->view->assign('itemPerPageHtml', $this->getItemsPerPageDropDownHtml());
224
        $this->view->assign('showResultLogHtml', $this->getShowResultLogCheckBoxHtml($setId, $quiPath));
225
        $this->view->assign('showFeVarsHtml', $this->getShowFeVarsCheckBoxHtml($setId, $quiPath));
226
        return $this->view->render();
227
    }
228
229
    /**
230
     * Outputs the CSV file and sets the correct headers
231
     */
232
    private function outputCsvFile(): void
233
    {
234
        if (! count($this->CSVaccu)) {
235
            MessageUtility::addWarningMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:message.canNotExportEmptyQueueToCsvText'));
236
            return;
237
        }
238
239
        $csvString = $this->csvWriter->arrayToCsv($this->CSVaccu);
240
241
        header('Content-Type: application/octet-stream');
242
        header('Content-Disposition: attachment; filename=CrawlerLog.csv');
243
        echo $csvString;
244
245
        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...
246
    }
247
248
    private function getIconFactory(): IconFactory
249
    {
250
        return GeneralUtility::makeInstance(IconFactory::class);
251
    }
252
253
    private function getDisplayLogFilterHtml(int $setId): string
254
    {
255
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.display') . ': ' . BackendUtility::getFuncMenu(
256
                $this->pageId,
257
                'SET[log_display]',
258
                $this->infoModuleController->MOD_SETTINGS['log_display'],
259
                $this->infoModuleController->MOD_MENU['log_display'],
260
                'index.php',
261
                '&setID=' . $setId
262
            );
263
    }
264
265
    private function getItemsPerPageDropDownHtml(): string
266
    {
267
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.itemsPerPage') . ': ' .
268
            BackendUtility::getFuncMenu(
269
                $this->pageId,
270
                'SET[itemsPerPage]',
271
                $this->infoModuleController->MOD_SETTINGS['itemsPerPage'],
272
                $this->infoModuleController->MOD_MENU['itemsPerPage']
273
            );
274
    }
275
276
    private function getShowResultLogCheckBoxHtml(int $setId, string $quiPart): string
277
    {
278
        return BackendUtility::getFuncCheck(
279
                $this->pageId,
280
                'SET[log_resultLog]',
281
                $this->infoModuleController->MOD_SETTINGS['log_resultLog'],
282
                'index.php',
283
                '&setID=' . $setId . $quiPart
284
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showresultlog');
285
    }
286
287
    private function getShowFeVarsCheckBoxHtml(int $setId, string $quiPart): string
288
    {
289
        return BackendUtility::getFuncCheck(
290
                $this->pageId,
291
                'SET[log_feVars]',
292
                $this->infoModuleController->MOD_SETTINGS['log_feVars'],
293
                'index.php',
294
                '&setID=' . $setId . $quiPart
295
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showfevars');
296
    }
297
298
    /**
299
     * Create the rows for display of the page tree
300
     * For each page a number of rows are shown displaying GET variable configuration
301
     *
302
     * @param array $logEntriesOfPage Log items of one page
303
     * @param string $titleString Title string
304
     * @return string HTML <tr> content (one or more)
305
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
306
     */
307
    private function drawLog_addRows(array $logEntriesOfPage, string $titleString): string
308
    {
309
        $colSpan = 9
310
            + ($this->infoModuleController->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
311
            + ($this->infoModuleController->MOD_SETTINGS['log_feVars'] ? 3 : 0);
312
313
        if (! empty($logEntriesOfPage)) {
314
            $setId = (int) GeneralUtility::_GP('setID');
315
            $refreshIcon = $this->getIconFactory()->getIcon('actions-system-refresh', Icon::SIZE_SMALL);
316
            // Traverse parameter combinations:
317
            $c = 0;
318
            $content = '';
319
            foreach ($logEntriesOfPage as $vv) {
320
                // Title column:
321
                if (! $c) {
322
                    $titleClm = '<td rowspan="' . count($logEntriesOfPage) . '">' . $titleString . '</td>';
323
                } else {
324
                    $titleClm = '';
325
                }
326
327
                // Result:
328
                $resLog = ResultHandler::getResultLog($vv);
329
330
                $resultData = $vv['result_data'] ? $this->jsonCompatibilityConverter->convert($vv['result_data']) : [];
331
                $resStatus = ResultHandler::getResStatus($resultData);
332
333
                // Compile row:
334
                $parameters = $this->jsonCompatibilityConverter->convert($vv['parameters']);
335
336
                // Put data into array:
337
                $rowData = [];
338
                if ($this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
339
                    $rowData['result_log'] = $resLog;
340
                } else {
341
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.immediate');
342
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
343
                }
344
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
345
                $url = htmlspecialchars($parameters['url'] ?? $parameters['alturl'], ENT_QUOTES | ENT_HTML5);
346
                $rowData['url'] = '<a href="' . $url . '" target="_newWIndow">' . $url . '</a>';
347
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'] ?: '';
348
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
349
                $rowData['set_id'] = (string) $vv['set_id'];
350
351
                if ($this->infoModuleController->MOD_SETTINGS['log_feVars']) {
352
                    $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

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