Issues (138)

Classes/Backend/RequestForm/LogRequestForm.php (1 issue)

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\Domain\Repository\QueueRepository;
11
use AOE\Crawler\Utility\MessageUtility;
12
use AOE\Crawler\Value\QueueFilter;
13
use AOE\Crawler\Writer\FileWriter\CsvWriter\CrawlerCsvWriter;
14
use AOE\Crawler\Writer\FileWriter\CsvWriter\CsvWriterInterface;
15
use Doctrine\DBAL\Query\QueryBuilder;
16
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
17
use TYPO3\CMS\Backend\Utility\BackendUtility;
18
use TYPO3\CMS\Core\Database\ConnectionPool;
19
use TYPO3\CMS\Core\Imaging\Icon;
20
use TYPO3\CMS\Core\Imaging\IconFactory;
21
use TYPO3\CMS\Core\Utility\DebugUtility;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Extbase\Object\ObjectManager;
24
use TYPO3\CMS\Fluid\View\StandaloneView;
25
use TYPO3\CMS\Info\Controller\InfoModuleController;
26
27
final class LogRequestForm extends AbstractRequestForm implements RequestFormInterface
28
{
29
    /**
30
     * @var StandaloneView
31
     */
32
    private $view;
33
34
    /**
35
     * @var JsonCompatibilityConverter
36
     */
37
    private $jsonCompatibilityConverter;
38
39
    /**
40
     * @var int
41
     */
42
    private $pageId;
43
44
    /**
45
     * @var bool
46
     */
47
    private $CSVExport = false;
48
49
    /**
50
     * @var InfoModuleController
51
     */
52
    private $infoModuleController;
53
54
    /**
55
     * @var QueryBuilder
56
     */
57
    private $queryBuilder;
58
59
    /**
60
     * @var CsvWriterInterface
61
     */
62
    private $csvWriter;
63
64
    /**
65
     * @var QueueRepository
66
     */
67
    private $queueRepository;
68
69
    /**
70
     * @var array
71
     */
72
    private $CSVaccu = [];
73
74 1
    public function __construct(StandaloneView $view, InfoModuleController $infoModuleController, array $extensionSettings)
75
    {
76 1
        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
77 1
        $this->view = $view;
78 1
        $this->infoModuleController = $infoModuleController;
79 1
        $this->jsonCompatibilityConverter = new JsonCompatibilityConverter();
80 1
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(QueueRepository::TABLE_NAME);
81 1
        $this->csvWriter = new CrawlerCsvWriter();
82 1
        $this->extensionSettings = $extensionSettings;
83 1
        $this->queueRepository = $objectManager->get(QueueRepository::class);
84 1
    }
85
86
    public function render($id, string $elementName, array $menuItems): string
87
    {
88
        $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . (int) GeneralUtility::_GP('qid_details') : '';
89
        $setId = (int) GeneralUtility::_GP('setID');
90
        $this->pageId = $id;
91
92
        return $this->getDepthDropDownHtml($id, $elementName, $menuItems)
93
            . $this->showLogAction($setId, $quiPart);
94
    }
95
96
    private function getDepthDropDownHtml($id, string $currentValue, array $menuItems): string
97
    {
98
        return BackendUtility::getFuncMenu(
99
            $id,
100
            'SET[depth]',
101
            $currentValue,
102
            $menuItems
103
        );
104
    }
105
106
    /*******************************
107
     *
108
     * Shows log of indexed URLs
109
     *
110
     ******************************/
111
112
    /**
113
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
114
     * @throws \TYPO3\CMS\Extbase\Object\Exception
115
     */
116
    private function showLogAction(int $setId, string $quiPath): string
117
    {
118
        $this->view->setTemplate('ShowLog');
119
        if (empty($this->pageId)) {
120
            $this->isErrorDetected = true;
121
            MessageUtility::addErrorMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noPageSelected'));
122
        } else {
123
            $this->findCrawler()->setID = GeneralUtility::md5int(microtime());
124
125
            $csvExport = GeneralUtility::_POST('_csv');
126
            $this->CSVExport = isset($csvExport);
127
128
            // Read URL:
129
            if (GeneralUtility::_GP('qid_read')) {
130
                $this->findCrawler()->readUrl((int) GeneralUtility::_GP('qid_read'), true);
131
            }
132
133
            // Look for set ID sent - if it is, we will display contents of that set:
134
            $showSetId = (int) GeneralUtility::_GP('setID');
135
136
            $queueId = GeneralUtility::_GP('qid_details');
137
            $this->view->assign('queueId', $queueId);
138
            $this->view->assign('setId', $showSetId);
139
            // Show details:
140
            if ($queueId) {
141
                // Get entry record:
142
                $q_entry = $this->queryBuilder
143
                    ->from(QueueRepository::TABLE_NAME)
144
                    ->select('*')
145
                    ->where(
146
                        $this->queryBuilder->expr()->eq('qid', $this->queryBuilder->createNamedParameter($queueId))
147
                    )
148
                    ->execute()
149
                    ->fetch();
150
151
                // Explode values
152
                $q_entry['parameters'] = $this->jsonCompatibilityConverter->convert($q_entry['parameters']);
153
                $q_entry['result_data'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']);
154
                $resStatus = ResultHandler::getResStatus($q_entry['result_data']);
155
                if (is_array($q_entry['result_data'])) {
156
                    $q_entry['result_data']['content'] = $this->jsonCompatibilityConverter->convert($q_entry['result_data']['content']);
157
                    if (! $this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
158
                        if (is_array($q_entry['result_data']['content'])) {
159
                            unset($q_entry['result_data']['content']['log']);
160
                        }
161
                    }
162
                }
163
164
                $this->view->assign('queueStatus', $resStatus);
165
                $this->view->assign('queueDetails', DebugUtility::viewArray($q_entry));
166
            } else {
167
                // Show list
168
                // Drawing tree:
169
                $tree = GeneralUtility::makeInstance(PageTreeView::class);
170
                $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
171
                $tree->init('AND ' . $perms_clause);
172
173
                // Set root row:
174
                $pageinfo = BackendUtility::readPageAccess(
175
                    $this->pageId,
176
                    $perms_clause
177
                );
178
                $HTML = $this->getIconFactory()->getIconForRecord('pages', $pageinfo, Icon::SIZE_SMALL)->render();
179
                $tree->tree[] = [
180
                    'row' => $pageinfo,
181
                    'HTML' => $HTML,
182
                ];
183
184
                // Get branch beneath:
185
                if ($this->infoModuleController->MOD_SETTINGS['depth']) {
186
                    $tree->getTree($this->pageId, $this->infoModuleController->MOD_SETTINGS['depth']);
187
                }
188
189
                // If Flush button is pressed, flush tables instead of selecting entries:
190
                if (GeneralUtility::_POST('_flush')) {
191
                    $doFlush = true;
192
                } elseif (GeneralUtility::_POST('_flush_all')) {
193
                    $doFlush = true;
194
                    $this->infoModuleController->MOD_SETTINGS['log_display'] = 'all';
195
                } else {
196
                    $doFlush = false;
197
                }
198
                $itemsPerPage = (int) $this->infoModuleController->MOD_SETTINGS['itemsPerPage'];
199
                $queueFilter = new QueueFilter($this->infoModuleController->MOD_SETTINGS['log_display']);
200
201
                if ($doFlush) {
202
                    $this->queueRepository->flushQueue($queueFilter);
203
                }
204
205
                // Traverse page tree:
206
                $count = 0;
207
                $logEntriesPerPage = [];
208
                foreach ($tree->tree as $data) {
209
                    $logEntriesOfPage = $this->queueRepository->getQueueEntriesForPageId(
210
                        (int) $data['row']['uid'],
211
                        $itemsPerPage,
212
                        $queueFilter
213
                    );
214
215
                    $logEntriesPerPage[] = $this->drawLog_addRows(
216
                        $logEntriesOfPage,
217
                        $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true)
218
                    );
219
                    if (++$count === 1000) {
220
                        break;
221
                    }
222
                }
223
224
                $this->view->assign('logEntriesPerPage', $logEntriesPerPage);
225
            }
226
227
            if ($this->CSVExport) {
228
                $this->outputCsvFile();
229
            }
230
        }
231
        $this->view->assign('showResultLog', (bool) $this->infoModuleController->MOD_SETTINGS['log_resultLog']);
232
        $this->view->assign('showFeVars', (bool) $this->infoModuleController->MOD_SETTINGS['log_feVars']);
233
        $this->view->assign('displayActions', 1);
234
        $this->view->assign('displayLogFilterHtml', $this->getDisplayLogFilterHtml($setId));
235
        $this->view->assign('itemPerPageHtml', $this->getItemsPerPageDropDownHtml());
236
        $this->view->assign('showResultLogHtml', $this->getShowResultLogCheckBoxHtml($setId, $quiPath));
237
        $this->view->assign('showFeVarsHtml', $this->getShowFeVarsCheckBoxHtml($setId, $quiPath));
238
        return $this->view->render();
239
    }
240
241
    /**
242
     * Outputs the CSV file and sets the correct headers
243
     */
244
    private function outputCsvFile(): void
245
    {
246
        if (! count($this->CSVaccu)) {
247
            MessageUtility::addWarningMessage($this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:message.canNotExportEmptyQueueToCsvText'));
248
            return;
249
        }
250
251
        $csvString = $this->csvWriter->arrayToCsv($this->CSVaccu);
252
253
        header('Content-Type: application/octet-stream');
254
        header('Content-Disposition: attachment; filename=CrawlerLog.csv');
255
        echo $csvString;
256
257
        exit;
258
    }
259
260
    private function getIconFactory(): IconFactory
261
    {
262
        return GeneralUtility::makeInstance(IconFactory::class);
263
    }
264
265
    private function getDisplayLogFilterHtml(int $setId): string
266
    {
267
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.display') . ': ' . BackendUtility::getFuncMenu(
268
                $this->pageId,
269
                'SET[log_display]',
270
                $this->infoModuleController->MOD_SETTINGS['log_display'],
271
                $this->infoModuleController->MOD_MENU['log_display'],
272
                'index.php',
273
                '&setID=' . $setId
274
            );
275
    }
276
277
    private function getItemsPerPageDropDownHtml(): string
278
    {
279
        return $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.itemsPerPage') . ': ' .
280
            BackendUtility::getFuncMenu(
281
                $this->pageId,
282
                'SET[itemsPerPage]',
283
                $this->infoModuleController->MOD_SETTINGS['itemsPerPage'],
284
                $this->infoModuleController->MOD_MENU['itemsPerPage']
285
            );
286
    }
287
288
    private function getShowResultLogCheckBoxHtml(int $setId, string $quiPart): string
289
    {
290
        return BackendUtility::getFuncCheck(
291
                $this->pageId,
292
                'SET[log_resultLog]',
293
                $this->infoModuleController->MOD_SETTINGS['log_resultLog'],
294
                'index.php',
295
                '&setID=' . $setId . $quiPart
296
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showresultlog');
297
    }
298
299
    private function getShowFeVarsCheckBoxHtml(int $setId, string $quiPart): string
300
    {
301
        return BackendUtility::getFuncCheck(
302
                $this->pageId,
303
                'SET[log_feVars]',
304
                $this->infoModuleController->MOD_SETTINGS['log_feVars'],
305
                'index.php',
306
                '&setID=' . $setId . $quiPart
307
            ) . '&nbsp;' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.showfevars');
308
    }
309
310
    /**
311
     * Create the rows for display of the page tree
312
     * For each page a number of rows are shown displaying GET variable configuration
313
     *
314
     * @param array $logEntriesOfPage Log items of one page
315
     * @param string $titleString Title string
316
     *
317
     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
318
     *
319
     * @psalm-return non-empty-list<array{titleRowSpan: positive-int, colSpan: int, title: string, noEntries?: string, trClass?: string, qid?: array{link: \TYPO3\CMS\Core\Http\Uri, link-text: string}, refresh?: array{link: \TYPO3\CMS\Core\Http\Uri, link-text: Icon, warning: Icon|string}, columns?: array{url: mixed|string, scheduled: string, exec_time: string, result_log: string, result_status: string, feUserGroupList: string, procInstructions: string, set_id: string, tsfe_id: string, tsfe_gr_list: string}}>
320
     */
321
    private function drawLog_addRows(array $logEntriesOfPage, string $titleString): array
322
    {
323
        $resultArray = [];
324
        $contentArray = [];
325
326
        $contentArray['titleRowSpan'] = 1;
327
        $contentArray['colSpan'] = 9
328
            + ($this->infoModuleController->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
329
            + ($this->infoModuleController->MOD_SETTINGS['log_feVars'] ? 3 : 0);
330
331
        if (! empty($logEntriesOfPage)) {
332
            $setId = (int) GeneralUtility::_GP('setID');
333
            $refreshIcon = $this->getIconFactory()->getIcon('actions-system-refresh', Icon::SIZE_SMALL);
334
            // Traverse parameter combinations:
335
            $firstIteration = true;
336
            foreach ($logEntriesOfPage as $vv) {
337
                // Title column:
338
                if ($firstIteration) {
339
                    $contentArray['titleRowSpan'] = count($logEntriesOfPage);
340
                    $contentArray['title'] = $titleString;
341
                } else {
342
                    $contentArray['title'] = '';
343
                    $contentArray['titleRowSpan'] = 1;
344
                }
345
346
                $firstIteration = false;
347
                $execTime = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
348
349
                // Result:
350
                $resLog = ResultHandler::getResultLog($vv);
351
352
                $resultData = $vv['result_data'] ? $this->jsonCompatibilityConverter->convert($vv['result_data']) : [];
353
                $resStatus = ResultHandler::getResStatus($resultData);
354
355
                // Compile row:
356
                $parameters = $this->jsonCompatibilityConverter->convert($vv['parameters']);
357
358
                // Put data into array:
359
                $rowData = [];
360
                if ($this->infoModuleController->MOD_SETTINGS['log_resultLog']) {
361
                    $rowData['result_log'] = $resLog;
362
                } else {
363
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : 0;
364
                    $rowData['exec_time'] = $execTime;
365
                }
366
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
367
                $url = htmlspecialchars($parameters['url'] ?? $parameters['alturl'], ENT_QUOTES | ENT_HTML5);
368
                $rowData['url'] = '<a href="' . $url . '" target="_newWIndow">' . $url . '</a>';
369
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'] ?: '';
370
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
371
                $rowData['set_id'] = (string) $vv['set_id'];
372
373
                if ($this->infoModuleController->MOD_SETTINGS['log_feVars']) {
374
                    $resFeVars = ResultHandler::getResFeVars($resultData ?: []);
0 ignored issues
show
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

374
                    $resFeVars = ResultHandler::getResFeVars(/** @scrutinizer ignore-type */ $resultData ?: []);
Loading history...
375
                    $rowData['tsfe_id'] = $resFeVars['id'] ?: '';
376
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'] ?: '';
377
                }
378
379
                $trClass = '';
380
                $warningIcon = '';
381
                if (str_contains($resStatus, 'Error:')) {
382
                    $trClass = 'bg-danger';
383
                    $warningIcon = $this->getIconFactory()->getIcon('actions-ban', Icon::SIZE_SMALL);
384
                }
385
386
                // Put rows together:
387
                $contentArray['trClass'] = $trClass;
388
                $contentArray['qid'] = [
389
                    'link' => UrlBuilder::getInfoModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]),
390
                    'link-text' => htmlspecialchars((string) $vv['qid'], ENT_QUOTES | ENT_HTML5),
391
                ];
392
                $contentArray['refresh'] = [
393
                    'link' => UrlBuilder::getInfoModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]),
394
                    'link-text' => $refreshIcon,
395
                    'warning' => $warningIcon,
396
                ];
397
398
                foreach ($rowData as $fKey => $value) {
399
                    if ($fKey === 'url') {
400
                        $contentArray['columns'][$fKey] = $value;
401
                    } else {
402
                        $contentArray['columns'][$fKey] = nl2br(htmlspecialchars((string) $value, ENT_QUOTES | ENT_HTML5));
403
                    }
404
                }
405
406
                $resultArray[] = $contentArray;
407
408
                if ($this->CSVExport) {
409
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
410
                    $csvExport['scheduled'] = BackendUtility::datetime($vv['scheduled']);
411
                    $csvExport['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
412
                    $csvExport['result_status'] = $contentArray['columns']['result_status'];
413
                    $csvExport['url'] = $contentArray['columns']['url'];
414
                    $csvExport['feUserGroupList'] = $contentArray['columns']['feUserGroupList'];
415
                    $csvExport['procInstructions'] = $contentArray['columns']['procInstructions'];
416
                    $csvExport['set_id'] = $contentArray['columns']['set_id'];
417
                    $csvExport['result_log'] = str_replace(chr(10), '// ', $resLog);
418
                    $csvExport['qid'] = $vv['qid'];
419
                    $this->CSVaccu[] = $csvExport;
420
                }
421
            }
422
        } else {
423
            $contentArray['title'] = $titleString;
424
            $contentArray['noEntries'] = $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noentries');
425
426
            $resultArray[] = $contentArray;
427
        }
428
429
        return $resultArray;
430
    }
431
}
432