Passed
Push — refactor/backendModule-ValueOb... ( 0f77d0...7f5344 )
by Tomas Norre
07:41
created

LogRequestForm::getIconFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace AOE\Crawler\Backend\RequestForm;
5
6
use AOE\Crawler\Backend\Helper\UrlBuilder;
7
use AOE\Crawler\Controller\CrawlerController;
8
use AOE\Crawler\Converter\JsonCompatibilityConverter;
9
use AOE\Crawler\Csv\CsvWriter;
0 ignored issues
show
Bug introduced by
The type AOE\Crawler\Csv\CsvWriter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

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

328
                    /** @scrutinizer ignore-call */ 
329
                    $resFeVars = $this->getResFeVars($resultData ?: []);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
329
                    $rowData['tsfe_id'] = $resFeVars['id'] ?: '';
330
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'] ?: '';
331
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'] ?: '';
332
                }
333
334
                $trClass = '';
335
                $warningIcon = '';
336
                if ($rowData['exec_time'] !== 0 && $resultData === false) {
337
                    $trClass = 'class="bg-danger"';
338
                    $warningIcon = $this->getIconFactory()->getIcon('actions-ban', Icon::SIZE_SMALL);
339
                }
340
341
                // Put rows together:
342
                $content .= '
343
                    <tr ' . $trClass . ' >
344
                        ' . $titleClm . '
345
                        <td><a href="' . UrlBuilder::getInfoModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars((string) $vv['qid']) . '</a></td>
346
                        <td><a href="' . UrlBuilder::getInfoModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]) . '">' . $refreshIcon . '</a>&nbsp;&nbsp;' . $warningIcon . '</td>';
347
                foreach ($rowData as $fKey => $value) {
348
                    if ($fKey === 'url') {
349
                        $content .= '<td>' . $value . '</td>';
350
                    } else {
351
                        $content .= '<td>' . nl2br(htmlspecialchars(strval($value))) . '</td>';
352
                    }
353
                }
354
                $content .= '</tr>';
355
                $c++;
356
357
                if ($this->CSVExport) {
358
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
359
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
360
                    $rowData['qid'] = $vv['qid'];
361
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
362
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
363
                    $this->CSVaccu[] = $rowData;
0 ignored issues
show
Bug Best Practice introduced by
The property CSVaccu does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
364
                }
365
            }
366
        } else {
367
            // Compile row:
368
            $content = '
369
                <tr>
370
                    <td>' . $titleString . '</td>
371
                    <td colspan="' . $colSpan . '"><em>' . $this->getLanguageService()->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noentries') . '</em></td>
372
                </tr>';
373
        }
374
375
        return $content;
376
    }
377
378
    /**
379
     * Extract the log information from the current row and retrieve it as formatted string.
380
     *
381
     * @param array $resultRow
382
     * @return string
383
     */
384
    private function getResultLog($resultRow)
385
    {
386
        $content = '';
387
        if (is_array($resultRow) && array_key_exists('result_data', $resultRow)) {
388
            $requestContent = $this->jsonCompatibilityConverter->convert($resultRow['result_data']) ?: ['content' => ''];
389
            if (! array_key_exists('content', $requestContent)) {
0 ignored issues
show
Bug introduced by
It seems like $requestContent can also be of type true; however, parameter $search of array_key_exists() 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

389
            if (! array_key_exists('content', /** @scrutinizer ignore-type */ $requestContent)) {
Loading history...
390
                return $content;
391
            }
392
            $requestResult = $this->jsonCompatibilityConverter->convert($requestContent['content']);
393
394
            if (is_array($requestResult) && array_key_exists('log', $requestResult)) {
395
                $content = implode(chr(10), $requestResult['log']);
396
            }
397
        }
398
        return $content;
399
    }
400
401
    private function getResStatus($requestContent): string
402
    {
403
        if (empty($requestContent)) {
404
            return '-';
405
        }
406
        if (! array_key_exists('content', $requestContent)) {
407
            return 'Content index does not exists in requestContent array';
408
        }
409
410
        $requestResult = $this->jsonCompatibilityConverter->convert($requestContent['content']);
411
        if (is_array($requestResult)) {
412
            if (empty($requestResult['errorlog'])) {
413
                return 'OK';
414
            }
415
            return implode("\n", $requestResult['errorlog']);
416
        }
417
418
        if (is_bool($requestResult)) {
0 ignored issues
show
introduced by
The condition is_bool($requestResult) is always true.
Loading history...
419
            return 'Error - no info, sorry!';
420
        }
421
422
        return 'Error: ' . substr(preg_replace('/\s+/', ' ', strip_tags($requestResult)), 0, 10000) . '...';
423
    }
424
}
425