Passed
Branch master (6c65a4)
by Christian
16:31
created

QueryView   F

Complexity

Total Complexity 225

Size/Duplication

Total Lines 1229
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1229
rs 0.6314
c 0
b 0
f 0
wmc 225

20 Methods

Rating   Name   Duplication   Size   Complexity  
C resultRowDisplay() 0 82 10
A __construct() 0 9 4
C getTreeList() 0 33 8
D makeValueList() 0 242 68
D csvRowTitles() 0 26 10
F getProcessedValueExtra() 0 104 36
A setFormName() 0 3 1
A cleanStoreQueryConfigs() 0 10 4
B saveQueryInAction() 0 43 4
D queryMaker() 0 66 12
C resultRowTitles() 0 27 8
C search() 0 69 9
A loadStoreQueryConfigs() 0 9 3
D procesStoreControl() 0 98 17
A form() 0 11 1
D getQueryResultCode() 0 84 17
A addToStoreQueryConfigs() 0 8 2
A csvValues() 0 9 4
A initStoreArray() 0 10 2
B makeStoreControl() 0 40 5

How to fix   Complexity   

Complex Class

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

1
<?php
2
namespace TYPO3\CMS\Core\Database;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use Doctrine\DBAL\DBALException;
18
use TYPO3\CMS\Backend\Utility\BackendUtility;
19
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20
use TYPO3\CMS\Core\Database\Query\QueryHelper;
21
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
22
use TYPO3\CMS\Core\Imaging\Icon;
23
use TYPO3\CMS\Core\Imaging\IconFactory;
24
use TYPO3\CMS\Core\Localization\LanguageService;
25
use TYPO3\CMS\Core\Messaging\FlashMessage;
26
use TYPO3\CMS\Core\Messaging\FlashMessageRendererResolver;
27
use TYPO3\CMS\Core\Type\Bitmask\Permission;
28
use TYPO3\CMS\Core\Utility\CsvUtility;
29
use TYPO3\CMS\Core\Utility\DebugUtility;
30
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
31
use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33
/**
34
 * Class used in module tools/dbint (advanced search) and which may hold code specific for that module
35
 * However the class has a general principle in it which may be used in the web/export module.
36
 */
37
class QueryView
38
{
39
    /**
40
     * @var string
41
     */
42
    public $storeList = 'search_query_smallparts,search_result_labels,labels_noprefix,show_deleted,queryConfig,queryTable,queryFields,queryLimit,queryOrder,queryOrderDesc,queryOrder2,queryOrder2Desc,queryGroup,search_query_makeQuery';
43
44
    /**
45
     * @var string
46
     */
47
    public $downloadScript = 'index.php';
48
49
    /**
50
     * @var int
51
     */
52
    public $formW = 48;
53
54
    /**
55
     * @var int
56
     */
57
    public $noDownloadB = 0;
58
59
    /**
60
     * @var array
61
     */
62
    public $hookArray = [];
63
64
    /**
65
     * @var string
66
     */
67
    protected $formName = '';
68
69
    /**
70
     * @var \TYPO3\CMS\Core\Imaging\IconFactory
71
     */
72
    protected $iconFactory;
73
74
    /**
75
     * @var array
76
     */
77
    protected $tableArray = [];
78
79
    /**
80
     * @var LanguageService
81
     */
82
    protected $languageService;
83
84
    /**
85
     * @var BackendUserAuthentication
86
     */
87
    protected $backendUserAuthentication;
88
89
    /**
90
     * Settings, usually from the controller (previously known from $GLOBALS['SOBE']->MOD_SETTINGS
91
     * @var array
92
     */
93
    protected $settings = [];
94
95
    /**
96
     * @var array information on the menu of this module
97
     */
98
    protected $menuItems = [];
99
100
    /**
101
     * @var string
102
     */
103
    protected $moduleName;
104
105
    /**
106
     * @param array $settings previously stored in $GLOBALS['SOBE']->MOD_SETTINGS
107
     * @param array $menuItems previously stored in $GLOBALS['SOBE']->MOD_MENU
108
     * @param string $moduleName previously stored in $GLOBALS['SOBE']->moduleName
109
     */
110
    public function __construct(array $settings = null, $menuItems = null, $moduleName = null)
111
    {
112
        $this->backendUserAuthentication = $GLOBALS['BE_USER'];
113
        $this->languageService = $GLOBALS['LANG'];
114
        $this->languageService->includeLLFile('EXT:core/Resources/Private/Language/locallang_t3lib_fullsearch.xlf');
115
        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
116
        $this->settings = $settings ?: $GLOBALS['SOBE']->MOD_SETTINGS;
117
        $this->menuItems = $menuItems ?: $GLOBALS['SOBE']->MOD_MENU;
118
        $this->moduleName = $moduleName ?: $GLOBALS['SOBE']->moduleName;
119
    }
120
121
    /**
122
     * Get form
123
     *
124
     * @return string
125
     */
126
    public function form()
127
    {
128
        $markup = [];
129
        $markup[] = '<div class="form-group">';
130
        $markup[] = '<input placeholder="Search Word" class="form-control" type="search" name="SET[sword]" value="'
131
            . htmlspecialchars($this->settings['sword']) . '">';
132
        $markup[] = '</div>';
133
        $markup[] = '<div class="form-group">';
134
        $markup[] = '<input class="btn btn-default" type="submit" name="submit" value="Search All Records">';
135
        $markup[] = '</div>';
136
        return implode(LF, $markup);
137
    }
138
139
    /**
140
     * Make store control
141
     *
142
     * @return string
143
     */
144
    public function makeStoreControl()
145
    {
146
        // Load/Save
147
        $storeArray = $this->initStoreArray();
148
149
        $opt = [];
150
        foreach ($storeArray as $k => $v) {
151
            $opt[] = '<option value="' . $k . '">' . htmlspecialchars($v) . '</option>';
152
        }
153
        // Actions:
154
        if (ExtensionManagementUtility::isLoaded('sys_action') && $this->backendUserAuthentication->isAdmin()) {
155
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_action');
156
            $queryBuilder->getRestrictions()->removeAll();
157
            $statement = $queryBuilder->select('uid', 'title')
158
                ->from('sys_action')
159
                ->where($queryBuilder->expr()->eq('type', $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT)))
160
                ->orderBy('title')
161
                ->execute();
162
            $opt[] = '<option value="0">__Save to Action:__</option>';
163
            while ($row = $statement->fetch()) {
164
                $opt[] = '<option value="-' . (int)$row['uid'] . '">' . htmlspecialchars(($row['title']
165
                        . ' [' . (int)$row['uid'] . ']')) . '</option>';
166
            }
167
        }
168
        $markup = [];
169
        $markup[] = '<div class="load-queries">';
170
        $markup[] = '  <div class="form-inline">';
171
        $markup[] = '    <div class="form-group">';
172
        $markup[] = '      <select class="form-control" name="storeControl[STORE]" onChange="document.forms[0]'
173
            . '[\'storeControl[title]\'].value= this.options[this.selectedIndex].value!=0 '
174
            . '? this.options[this.selectedIndex].text : \'\';">' . implode(LF, $opt) . '</select>';
175
        $markup[] = '      <input class="form-control" name="storeControl[title]" value="" type="text" max="80">';
176
        $markup[] = '      <input class="btn btn-default" type="submit" name="storeControl[LOAD]" value="Load">';
177
        $markup[] = '      <input class="btn btn-default" type="submit" name="storeControl[SAVE]" value="Save">';
178
        $markup[] = '      <input class="btn btn-default" type="submit" name="storeControl[REMOVE]" value="Remove">';
179
        $markup[] = '    </div>';
180
        $markup[] = '  </div>';
181
        $markup[] = '</div>';
182
183
        return implode(LF, $markup);
184
    }
185
186
    /**
187
     * Init store array
188
     *
189
     * @return array
190
     */
191
    public function initStoreArray()
192
    {
193
        $storeArray = [
194
            '0' => '[New]'
195
        ];
196
        $savedStoreArray = unserialize($this->settings['storeArray']);
197
        if (is_array($savedStoreArray)) {
198
            $storeArray = array_merge($storeArray, $savedStoreArray);
199
        }
200
        return $storeArray;
201
    }
202
203
    /**
204
     * Clean store query configs
205
     *
206
     * @param array $storeQueryConfigs
207
     * @param array $storeArray
208
     * @return array
209
     */
210
    public function cleanStoreQueryConfigs($storeQueryConfigs, $storeArray)
211
    {
212
        if (is_array($storeQueryConfigs)) {
213
            foreach ($storeQueryConfigs as $k => $v) {
214
                if (!isset($storeArray[$k])) {
215
                    unset($storeQueryConfigs[$k]);
216
                }
217
            }
218
        }
219
        return $storeQueryConfigs;
220
    }
221
222
    /**
223
     * Add to store query configs
224
     *
225
     * @param array $storeQueryConfigs
226
     * @param int $index
227
     * @return array
228
     */
229
    public function addToStoreQueryConfigs($storeQueryConfigs, $index)
230
    {
231
        $keyArr = explode(',', $this->storeList);
232
        $storeQueryConfigs[$index] = [];
233
        foreach ($keyArr as $k) {
234
            $storeQueryConfigs[$index][$k] = $this->settings[$k];
235
        }
236
        return $storeQueryConfigs;
237
    }
238
239
    /**
240
     * Save query in action
241
     *
242
     * @param int $uid
243
     * @return int
244
     */
245
    public function saveQueryInAction($uid)
246
    {
247
        if (ExtensionManagementUtility::isLoaded('sys_action')) {
248
            $keyArr = explode(',', $this->storeList);
249
            $saveArr = [];
250
            foreach ($keyArr as $k) {
251
                $saveArr[$k] = $this->settings[$k];
252
            }
253
            // Show query
254
            if ($saveArr['queryTable']) {
255
                /** @var \TYPO3\CMS\Core\Database\QueryGenerator */
256
                $queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
257
                $queryGenerator->init('queryConfig', $saveArr['queryTable']);
258
                $queryGenerator->makeSelectorTable($saveArr);
259
                $queryGenerator->enablePrefix = 1;
260
                $queryString = $queryGenerator->getQuery($queryGenerator->queryConfig);
261
262
                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
263
                    ->getQueryBuilderForTable($queryGenerator->table);
264
                $queryBuilder->getRestrictions()->removeAll()
265
                    ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
266
                $rowCount = $queryBuilder->count('*')
267
                    ->from($queryGenerator->table)
268
                    ->where(QueryHelper::stripLogicalOperatorPrefix($queryString))
269
                    ->execute()->fetchColumn(0);
270
271
                $t2DataValue = [
272
                    'qC' => $saveArr,
273
                    'qCount' => $rowCount,
274
                    'qSelect' => $queryGenerator->getSelectQuery($queryString),
275
                    'qString' => $queryString
276
                ];
277
                GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('sys_action')
278
                    ->update(
279
                        'sys_action',
280
                        ['t2_data' => serialize($t2DataValue)],
281
                        ['uid' => (int)$uid],
282
                        ['t2_data' => Connection::PARAM_LOB]
283
                    );
284
            }
285
            return 1;
286
        }
287
        return null;
288
    }
289
290
    /**
291
     * Load store query configs
292
     *
293
     * @param array $storeQueryConfigs
294
     * @param int $storeIndex
295
     * @param array $writeArray
296
     * @return array
297
     */
298
    public function loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray)
299
    {
300
        if ($storeQueryConfigs[$storeIndex]) {
301
            $keyArr = explode(',', $this->storeList);
302
            foreach ($keyArr as $k) {
303
                $writeArray[$k] = $storeQueryConfigs[$storeIndex][$k];
304
            }
305
        }
306
        return $writeArray;
307
    }
308
309
    /**
310
     * Process store control
311
     *
312
     * @return string
313
     */
314
    public function procesStoreControl()
315
    {
316
        $storeArray = $this->initStoreArray();
317
        $storeQueryConfigs = unserialize($this->settings['storeQueryConfigs']);
318
        $storeControl = GeneralUtility::_GP('storeControl');
319
        $storeIndex = (int)$storeControl['STORE'];
320
        $saveStoreArray = 0;
321
        $writeArray = [];
322
        $msg = '';
323
        if (is_array($storeControl)) {
324
            if ($storeControl['LOAD']) {
325
                if ($storeIndex > 0) {
326
                    $writeArray = $this->loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray);
327
                    $saveStoreArray = 1;
328
                    $flashMessage = GeneralUtility::makeInstance(
329
                        FlashMessage::class,
330
                        sprintf($this->languageService->getLL('query_loaded'), $storeArray[$storeIndex])
331
                    );
332
                } elseif ($storeIndex < 0 && ExtensionManagementUtility::isLoaded('sys_action')) {
333
                    $actionRecord = BackendUtility::getRecord('sys_action', abs($storeIndex));
334
                    if (is_array($actionRecord)) {
335
                        $dA = unserialize($actionRecord['t2_data']);
336
                        $dbSC = [];
337
                        if (is_array($dA['qC'])) {
338
                            $dbSC[0] = $dA['qC'];
339
                        }
340
                        $writeArray = $this->loadStoreQueryConfigs($dbSC, '0', $writeArray);
341
                        $saveStoreArray = 1;
342
                        $flashMessage = GeneralUtility::makeInstance(
343
                            FlashMessage::class,
344
                            sprintf($this->languageService->getLL('query_from_action_loaded'), $actionRecord['title'])
345
                        );
346
                    }
347
                }
348
            } elseif ($storeControl['SAVE']) {
349
                if ($storeIndex < 0) {
350
                    $qOK = $this->saveQueryInAction(abs($storeIndex));
351
                    if ($qOK) {
352
                        $flashMessage = GeneralUtility::makeInstance(
353
                            FlashMessage::class,
354
                            $this->languageService->getLL('query_saved')
355
                        );
356
                    } else {
357
                        $flashMessage = GeneralUtility::makeInstance(
358
                            FlashMessage::class,
359
                            $this->languageService->getLL('query_notsaved'),
360
                            '',
361
                            FlashMessage::ERROR
362
                        );
363
                    }
364
                } else {
365
                    if (trim($storeControl['title'])) {
366
                        if ($storeIndex > 0) {
367
                            $storeArray[$storeIndex] = $storeControl['title'];
368
                        } else {
369
                            $storeArray[] = $storeControl['title'];
370
                            end($storeArray);
371
                            $storeIndex = key($storeArray);
372
                        }
373
                        $storeQueryConfigs = $this->addToStoreQueryConfigs($storeQueryConfigs, $storeIndex);
374
                        $saveStoreArray = 1;
375
                        $flashMessage = GeneralUtility::makeInstance(
376
                            FlashMessage::class,
377
                            $this->languageService->getLL('query_saved')
378
                        );
379
                    }
380
                }
381
            } elseif ($storeControl['REMOVE']) {
382
                if ($storeIndex > 0) {
383
                    $flashMessage = GeneralUtility::makeInstance(
384
                        FlashMessage::class,
385
                        sprintf($this->languageService->getLL('query_removed'), $storeArray[$storeControl['STORE']])
386
                    );
387
                    // Removing
388
                    unset($storeArray[$storeControl['STORE']]);
389
                    $saveStoreArray = 1;
390
                }
391
            }
392
            if (!empty($flashMessage)) {
393
                $msg = GeneralUtility::makeInstance(FlashMessageRendererResolver::class)
394
                    ->resolve()
395
                    ->render([$flashMessage]);
396
            }
397
        }
398
        if ($saveStoreArray) {
399
            // Making sure, index 0 is not set!
400
            unset($storeArray[0]);
401
            $writeArray['storeArray'] = serialize($storeArray);
402
            $writeArray['storeQueryConfigs'] =
403
                serialize($this->cleanStoreQueryConfigs($storeQueryConfigs, $storeArray));
404
            $this->settings = BackendUtility::getModuleData(
405
                $this->menuItems,
406
                $writeArray,
407
                $this->moduleName,
408
                'ses'
409
            );
410
        }
411
        return $msg;
412
    }
413
414
    /**
415
     * Query marker
416
     *
417
     * @return string
418
     */
419
    public function queryMaker()
420
    {
421
        $output = '';
422
        $this->hookArray = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3lib_fullsearch'] ?? [];
423
        $msg = $this->procesStoreControl();
424
        if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableStoreControl']) {
425
            $output .= '<h2>Load/Save Query</h2>';
426
            $output .= '<div>' . $this->makeStoreControl() . '</div>';
427
            $output .= $msg;
428
        }
429
        // Query Maker:
430
        $queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
431
        $queryGenerator->init('queryConfig', $this->settings['queryTable']);
432
        if ($this->formName) {
433
            $queryGenerator->setFormName($this->formName);
434
        }
435
        $tmpCode = $queryGenerator->makeSelectorTable($this->settings);
436
        $output .= '<div id="query"></div>' . '<h2>Make query</h2><div>' . $tmpCode . '</div>';
437
        $mQ = $this->settings['search_query_makeQuery'];
438
        // Make form elements:
439
        if ($queryGenerator->table && is_array($GLOBALS['TCA'][$queryGenerator->table])) {
440
            if ($mQ) {
441
                // Show query
442
                $queryGenerator->enablePrefix = 1;
443
                $queryString = $queryGenerator->getQuery($queryGenerator->queryConfig);
444
                $selectQueryString = $queryGenerator->getSelectQuery($queryString);
445
                $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($queryGenerator->table);
446
447
                $isConnectionMysql = (bool)(strpos($connection->getServerVersion(), 'MySQL') === 0);
448
                $fullQueryString = '';
449
                try {
450
                    if ($mQ === 'explain' && $isConnectionMysql) {
451
                        // EXPLAIN is no ANSI SQL, for now this is only executed on mysql
452
                        // @todo: Move away from getSelectQuery() or model differently
453
                        $fullQueryString = 'EXPLAIN ' . $selectQueryString;
454
                        $dataRows = $connection->executeQuery('EXPLAIN ' . $selectQueryString)->fetchAll();
455
                    } elseif ($mQ === 'count') {
456
                        $queryBuilder = $connection->createQueryBuilder();
457
                        $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
458
                        $dataRows = $queryBuilder->count('*')
459
                            ->from($queryGenerator->table)
460
                            ->where(QueryHelper::stripLogicalOperatorPrefix($queryString));
461
                        $fullQueryString = $queryBuilder->getSQL();
462
                        $queryBuilder->execute()->fetchColumn(0);
463
                        $dataRows = [$dataRows];
464
                    } else {
465
                        $fullQueryString = $selectQueryString;
466
                        $dataRows = $connection->executeQuery($selectQueryString)->fetchAll();
467
                    }
468
                    if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableShowSQLQuery']) {
469
                        $output .= '<h2>SQL query</h2><div><pre>' . htmlspecialchars($fullQueryString) . '</pre></div>';
470
                    }
471
                    $cPR = $this->getQueryResultCode($mQ, $dataRows, $queryGenerator->table);
472
                    $output .= '<h2>' . $cPR['header'] . '</h2><div>' . $cPR['content'] . '</div>';
473
                } catch (DBALException $e) {
474
                    if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableShowSQLQuery']) {
475
                        $output .= '<h2>SQL query</h2><div><pre>' . htmlspecialchars($fullQueryString) . '</pre></div>';
476
                    }
477
                    $out = '<p><strong>Error: <span class="text-danger">'
478
                        . $e->getMessage()
479
                        . '</span></strong></p>';
480
                    $output .= '<h2>SQL error</h2><div>' . $out . '</div>';
481
                }
482
            }
483
        }
484
        return '<div class="query-builder">' . $output . '</div>';
485
    }
486
487
    /**
488
     * Get query result code
489
     *
490
     * @param string $type
491
     * @param array $dataRows Rows to display
492
     * @param string $table
493
     * @return string
494
     */
495
    public function getQueryResultCode($type, array $dataRows, $table)
496
    {
497
        $out = '';
498
        $cPR = [];
499
        switch ($type) {
500
            case 'count':
501
                $cPR['header'] = 'Count';
502
                $cPR['content'] = '<BR><strong>' . $dataRows[0] . '</strong> records selected.';
503
                break;
504
            case 'all':
505
                $rowArr = [];
506
                $dataRow = null;
507
                foreach ($dataRows as $dataRow) {
508
                    $rowArr[] = $this->resultRowDisplay($dataRow, $GLOBALS['TCA'][$table], $table);
509
                }
510
                if (is_array($this->hookArray['beforeResultTable'])) {
511
                    foreach ($this->hookArray['beforeResultTable'] as $_funcRef) {
512
                        $out .= GeneralUtility::callUserFunction($_funcRef, $this->settings, $this);
513
                    }
514
                }
515
                if (!empty($rowArr)) {
516
                    $out .= '<table class="table table-striped table-hover">'
517
                        . $this->resultRowTitles($dataRow, $GLOBALS['TCA'][$table], $table) . implode(LF, $rowArr)
518
                        . '</table>';
519
                }
520
                if (!$out) {
521
                    $flashMessage = GeneralUtility::makeInstance(
522
                        FlashMessage::class,
523
                        'No rows selected!',
0 ignored issues
show
Bug introduced by
'No rows selected!' of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

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

523
                        /** @scrutinizer ignore-type */ 'No rows selected!',
Loading history...
524
                        '',
525
                        FlashMessage::INFO
526
                    );
527
                    GeneralUtility::makeInstance(FlashMessageRendererResolver::class)
528
                        ->resolve()
529
                        ->render([$flashMessage]);
530
                }
531
                $cPR['header'] = 'Result';
532
                $cPR['content'] = $out;
533
                break;
534
            case 'csv':
535
                $rowArr = [];
536
                $first = 1;
537
                foreach ($dataRows as $dataRow) {
538
                    if ($first) {
539
                        $rowArr[] = $this->csvValues(array_keys($dataRow), ',', '');
540
                        $first = 0;
541
                    }
542
                    $rowArr[] = $this->csvValues($dataRow, ',', '"', $GLOBALS['TCA'][$table], $table);
543
                }
544
                if (!empty($rowArr)) {
545
                    $out .= '<textarea name="whatever" rows="20" class="text-monospace" style="width:100%">'
546
                        . htmlspecialchars(implode(LF, $rowArr))
547
                        . '</textarea>';
548
                    if (!$this->noDownloadB) {
549
                        $out .= '<br><input class="btn btn-default" type="submit" name="download_file" '
550
                            . 'value="Click to download file" onClick="window.location.href=\'' . $this->downloadScript
551
                            . '\';">';
552
                    }
553
                    // Downloads file:
554
                    // @todo: args. routing anyone?
555
                    if (GeneralUtility::_GP('download_file')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression TYPO3\CMS\Core\Utility\G...y::_GP('download_file') of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
556
                        $filename = 'TYPO3_' . $table . '_export_' . date('dmy-Hi') . '.csv';
557
                        $mimeType = 'application/octet-stream';
558
                        header('Content-Type: ' . $mimeType);
559
                        header('Content-Disposition: attachment; filename=' . $filename);
560
                        echo implode(CRLF, $rowArr);
561
                        die;
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...
562
                    }
563
                }
564
                if (!$out) {
565
                    $out = '<em>No rows selected!</em>';
566
                }
567
                $cPR['header'] = 'Result';
568
                $cPR['content'] = $out;
569
                break;
570
            case 'explain':
571
            default:
572
                foreach ($dataRows as $dataRow) {
573
                    $out .= '<br />' . DebugUtility::viewArray($dataRow);
574
                }
575
                $cPR['header'] = 'Explain SQL query';
576
                $cPR['content'] = $out;
577
        }
578
        return $cPR;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $cPR returns the type string[] which is incompatible with the documented return type string.
Loading history...
579
    }
580
581
    /**
582
     * CSV values
583
     *
584
     * @param array $row
585
     * @param string $delim
586
     * @param string $quote
587
     * @param array $conf
588
     * @param string $table
589
     * @return string A single line of CSV
590
     */
591
    public function csvValues($row, $delim = ',', $quote = '"', $conf = [], $table = '')
592
    {
593
        $valueArray = $row;
594
        if ($this->settings['search_result_labels'] && $table) {
595
            foreach ($valueArray as $key => $val) {
596
                $valueArray[$key] = $this->getProcessedValueExtra($table, $key, $val, $conf, ';');
597
            }
598
        }
599
        return CsvUtility::csvValues($valueArray, $delim, $quote);
600
    }
601
602
    /**
603
     * Search
604
     *
605
     * @return string
606
     */
607
    public function search()
608
    {
609
        $swords = $this->settings['sword'];
610
        $out = '';
611
        if ($swords) {
612
            foreach ($GLOBALS['TCA'] as $table => $value) {
613
                // Get fields list
614
                $conf = $GLOBALS['TCA'][$table];
615
                // Avoid querying tables with no columns
616
                if (empty($conf['columns'])) {
617
                    continue;
618
                }
619
                $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
620
                $tableColumns = $connection->getSchemaManager()->listTableColumns($table);
621
                $fieldsInDatabase = [];
622
                foreach ($tableColumns as $column) {
623
                    $fieldsInDatabase[] = $column->getName();
624
                }
625
                $fields = array_intersect(array_keys($conf['columns']), $fieldsInDatabase);
626
627
                $queryBuilder = $connection->createQueryBuilder();
628
                $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
629
                $queryBuilder->count('*')->from($table);
630
                $likes = [];
631
                $excapedLikeString = '%' . $queryBuilder->escapeLikeWildcards($swords) . '%';
632
                foreach ($fields as $field) {
633
                    $likes[] = $queryBuilder->expr()->like(
634
                        $field,
635
                        $queryBuilder->createNamedParameter($excapedLikeString, \PDO::PARAM_STR)
636
                    );
637
                }
638
                $count = $queryBuilder->orWhere(...$likes)->execute()->fetchColumn(0);
639
640
                if ($count > 0) {
641
                    $queryBuilder = $connection->createQueryBuilder();
642
                    $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
643
                    $queryBuilder->select('uid', $conf['ctrl']['label'])
644
                        ->from($table)
645
                        ->setMaxResults(200);
646
                    $likes = [];
647
                    foreach ($fields as $field) {
648
                        $likes[] = $queryBuilder->expr()->like(
649
                            $field,
650
                            $queryBuilder->createNamedParameter($excapedLikeString, \PDO::PARAM_STR)
651
                        );
652
                    }
653
                    $statement = $queryBuilder->orWhere(...$likes)->execute();
654
                    $lastRow = null;
655
                    $rowArr = [];
656
                    while ($row = $statement->fetch()) {
657
                        $rowArr[] = $this->resultRowDisplay($row, $conf, $table);
658
                        $lastRow = $row;
659
                    }
660
                    $markup = [];
661
                    $markup[] = '<div class="panel panel-default">';
662
                    $markup[] = '  <div class="panel-heading">';
663
                    $markup[] = htmlspecialchars($this->languageService->sL($conf['ctrl']['title'])) . ' (' . $count . ')';
664
                    $markup[] = '  </div>';
665
                    $markup[] = '  <table class="table table-striped table-hover">';
666
                    $markup[] = $this->resultRowTitles($lastRow, $conf, $table);
667
                    $markup[] = implode(LF, $rowArr);
668
                    $markup[] = '  </table>';
669
                    $markup[] = '</div>';
670
671
                    $out .= implode(LF, $markup);
672
                }
673
            }
674
        }
675
        return $out;
676
    }
677
678
    /**
679
     * Result row display
680
     *
681
     * @param array $row
682
     * @param array $conf
683
     * @param string $table
684
     * @return string
685
     */
686
    public function resultRowDisplay($row, $conf, $table)
687
    {
688
        $out = '<tr>';
689
        foreach ($row as $fieldName => $fieldValue) {
690
            if (GeneralUtility::inList($this->settings['queryFields'], $fieldName)
691
                || !$this->settings['queryFields']
692
                && $fieldName !== 'pid'
693
                && $fieldName !== 'deleted'
694
            ) {
695
                if ($this->settings['search_result_labels']) {
696
                    $fVnew = $this->getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, '<br />');
697
                } else {
698
                    $fVnew = htmlspecialchars($fieldValue);
699
                }
700
                $out .= '<td>' . $fVnew . '</td>';
701
            }
702
        }
703
        $out .= '<td>';
704
        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
705
        $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
706
707
        if (!$row['deleted']) {
708
            $out .= '<div class="btn-group" role="group">';
709
            $url = (string)$uriBuilder->buildUriFromRoute('record_edit', [
710
                'edit' => [
711
                    $table => [
712
                        $row['uid'] => 'edit'
713
                    ]
714
                ],
715
                'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
716
                    . GeneralUtility::implodeArrayForUrl('SET', (array)GeneralUtility::_POST('SET'))
717
            ]);
718
            $out .= '<a class="btn btn-default" href="' . htmlspecialchars($url) . '">'
719
                . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>';
720
            $out .= '</div><div class="btn-group" role="group">';
721
            $out .= '<a class="btn btn-default" href="#" onClick="top.launchView(\'' . $table . '\',' . $row['uid']
722
                . ');return false;">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render()
723
                . '</a>';
724
            $out .= '</div>';
725
        } else {
726
            $out .= '<div class="btn-group" role="group">';
727
            $out .= '<a class="btn btn-default" href="' . htmlspecialchars((string)$uriBuilder->buildUriFromRoute('tce_db', [
728
                        'cmd' => [
729
                            $table => [
730
                                $row['uid'] => [
731
                                    'undelete' => 1
732
                                ]
733
                            ]
734
                        ],
735
                        'redirect' => GeneralUtility::linkThisScript()
736
                    ])) . '" title="' . htmlspecialchars($this->languageService->getLL('undelete_only')) . '">';
737
            $out .= $this->iconFactory->getIcon('actions-edit-restore', Icon::SIZE_SMALL)->render() . '</a>';
738
            $formEngineParameters = [
739
                'edit' => [
740
                    $table => [
741
                        $row['uid'] => 'edit'
742
                    ]
743
                ],
744
                'returnUrl' => GeneralUtility::linkThisScript()
745
            ];
746
            $redirectUrl = (string)$uriBuilder->buildUriFromRoute('record_edit', $formEngineParameters);
747
            $out .= '<a class="btn btn-default" href="' . htmlspecialchars((string)$uriBuilder->buildUriFromRoute('tce_db', [
748
                    'cmd' => [
749
                        $table => [
750
                            $row['uid'] => [
751
                                'undelete' => 1
752
                            ]
753
                        ]
754
                    ],
755
                    'redirect' => $redirectUrl
756
                ])) . '" title="' . htmlspecialchars($this->languageService->getLL('undelete_and_edit')) . '">';
757
            $out .= $this->iconFactory->getIcon('actions-edit-restore-edit', Icon::SIZE_SMALL)->render() . '</a>';
758
            $out .= '</div>';
759
        }
760
        $_params = [$table => $row];
761
        if (is_array($this->hookArray['additionalButtons'])) {
762
            foreach ($this->hookArray['additionalButtons'] as $_funcRef) {
763
                $out .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
764
            }
765
        }
766
        $out .= '</td></tr>';
767
        return $out;
768
    }
769
770
    /**
771
     * Get processed value extra
772
     *
773
     * @param string $table
774
     * @param string $fieldName
775
     * @param string $fieldValue
776
     * @param array $conf Not used
777
     * @param string $splitString
778
     * @return string
779
     */
780
    public function getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, $splitString)
0 ignored issues
show
Unused Code introduced by
The parameter $conf is not used and could be removed. ( Ignorable by Annotation )

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

780
    public function getProcessedValueExtra($table, $fieldName, $fieldValue, /** @scrutinizer ignore-unused */ $conf, $splitString)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
781
    {
782
        $out = '';
783
        $fields = [];
784
        // Analysing the fields in the table.
785
        if (is_array($GLOBALS['TCA'][$table])) {
786
            $fC = $GLOBALS['TCA'][$table]['columns'][$fieldName];
787
            $fields = $fC['config'];
788
            $fields['exclude'] = $fC['exclude'];
789
            if (is_array($fC) && $fC['label']) {
790
                $fields['label'] = preg_replace('/:$/', '', trim($this->languageService->sL($fC['label'])));
791
                switch ($fields['type']) {
792
                    case 'input':
793
                        if (preg_match('/int|year/i', $fields['eval'])) {
794
                            $fields['type'] = 'number';
795
                        } elseif (preg_match('/time/i', $fields['eval'])) {
796
                            $fields['type'] = 'time';
797
                        } elseif (preg_match('/date/i', $fields['eval'])) {
798
                            $fields['type'] = 'date';
799
                        } else {
800
                            $fields['type'] = 'text';
801
                        }
802
                        break;
803
                    case 'check':
804
                        if (!$fields['items']) {
805
                            $fields['type'] = 'boolean';
806
                        } else {
807
                            $fields['type'] = 'binary';
808
                        }
809
                        break;
810
                    case 'radio':
811
                        $fields['type'] = 'multiple';
812
                        break;
813
                    case 'select':
814
                        $fields['type'] = 'multiple';
815
                        if ($fields['foreign_table']) {
816
                            $fields['type'] = 'relation';
817
                        }
818
                        if ($fields['special']) {
819
                            $fields['type'] = 'text';
820
                        }
821
                        break;
822
                    case 'group':
823
                        $fields['type'] = 'files';
824
                        if ($fields['internal_type'] === 'db') {
825
                            $fields['type'] = 'relation';
826
                        }
827
                        break;
828
                    case 'user':
829
                    case 'flex':
830
                    case 'passthrough':
831
                    case 'none':
832
                    case 'text':
833
                    default:
834
                        $fields['type'] = 'text';
835
                }
836
            } else {
837
                $fields['label'] = '[FIELD: ' . $fieldName . ']';
838
                switch ($fieldName) {
839
                    case 'pid':
840
                        $fields['type'] = 'relation';
841
                        $fields['allowed'] = 'pages';
842
                        break;
843
                    case 'cruser_id':
844
                        $fields['type'] = 'relation';
845
                        $fields['allowed'] = 'be_users';
846
                        break;
847
                    case 'tstamp':
848
                    case 'crdate':
849
                        $fields['type'] = 'time';
850
                        break;
851
                    default:
852
                        $fields['type'] = 'number';
853
                }
854
            }
855
        }
856
        switch ($fields['type']) {
857
            case 'date':
858
                if ($fieldValue != -1) {
859
                    $out = strftime('%d-%m-%Y', $fieldValue);
0 ignored issues
show
Bug introduced by
$fieldValue of type string is incompatible with the type integer expected by parameter $timestamp of strftime(). ( Ignorable by Annotation )

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

859
                    $out = strftime('%d-%m-%Y', /** @scrutinizer ignore-type */ $fieldValue);
Loading history...
860
                }
861
                break;
862
            case 'time':
863
                if ($fieldValue != -1) {
864
                    if ($splitString === '<br />') {
865
                        $out = strftime('%H:%M' . $splitString . '%d-%m-%Y', $fieldValue);
866
                    } else {
867
                        $out = strftime('%H:%M %d-%m-%Y', $fieldValue);
868
                    }
869
                }
870
                break;
871
            case 'multiple':
872
            case 'binary':
873
            case 'relation':
874
                $out = $this->makeValueList($fieldName, $fieldValue, $fields, $table, $splitString);
875
                break;
876
            case 'boolean':
877
                $out = $fieldValue ? 'True' : 'False';
878
                break;
879
            case 'files':
880
            default:
881
                $out = htmlspecialchars($fieldValue);
882
        }
883
        return $out;
884
    }
885
886
    /**
887
     * Get tree list
888
     *
889
     * @param int $id
890
     * @param int $depth
891
     * @param int $begin
892
     * @param string $permsClause
893
     *
894
     * @return string
895
     */
896
    public function getTreeList($id, $depth, $begin = 0, $permsClause = null)
897
    {
898
        $depth = (int)$depth;
899
        $begin = (int)$begin;
900
        $id = (int)$id;
901
        if ($id < 0) {
902
            $id = abs($id);
903
        }
904
        if ($begin == 0) {
905
            $theList = $id;
906
        } else {
907
            $theList = '';
908
        }
909
        if ($id && $depth > 0) {
910
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
911
            $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
912
            $statement = $queryBuilder->select('uid')
913
                ->from('pages')
914
                ->where(
915
                    $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)),
916
                    QueryHelper::stripLogicalOperatorPrefix($permsClause)
0 ignored issues
show
Bug introduced by
It seems like $permsClause can also be of type null; however, parameter $constraint of TYPO3\CMS\Core\Database\...LogicalOperatorPrefix() does only seem to accept string, 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

916
                    QueryHelper::stripLogicalOperatorPrefix(/** @scrutinizer ignore-type */ $permsClause)
Loading history...
917
                )
918
                ->execute();
919
            while ($row = $statement->fetch()) {
920
                if ($begin <= 0) {
921
                    $theList .= ',' . $row['uid'];
922
                }
923
                if ($depth > 1) {
924
                    $theList .= $this->getTreeList($row['uid'], $depth - 1, $begin - 1, $permsClause);
925
                }
926
            }
927
        }
928
        return $theList;
929
    }
930
931
    /**
932
     * Make value list
933
     *
934
     * @param string $fieldName
935
     * @param string $fieldValue
936
     * @param array $conf
937
     * @param string $table
938
     * @param string $splitString
939
     * @return string
940
     */
941
    public function makeValueList($fieldName, $fieldValue, $conf, $table, $splitString)
942
    {
943
        $fieldSetup = $conf;
944
        $out = '';
945
        if ($fieldSetup['type'] === 'files') {
946
            $d = dir(PATH_site . $fieldSetup['uploadfolder']);
0 ignored issues
show
Bug introduced by
The call to dir() has too few arguments starting with context. ( Ignorable by Annotation )

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

946
            $d = /** @scrutinizer ignore-call */ dir(PATH_site . $fieldSetup['uploadfolder']);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
947
            while (false !== ($entry = $d->read())) {
948
                if ($entry === '.' || $entry === '..') {
949
                    continue;
950
                }
951
                $fileArray[] = $entry;
952
            }
953
            $d->close();
954
            natcasesort($fileArray);
955
            foreach ($fileArray as $fileName) {
956
                if (GeneralUtility::inList($fieldValue, $fileName) || $fieldValue == $fileName) {
957
                    if (!$out) {
958
                        $out = htmlspecialchars($fileName);
959
                    } else {
960
                        $out .= $splitString . htmlspecialchars($fileName);
961
                    }
962
                }
963
            }
964
        }
965
        if ($fieldSetup['type'] === 'multiple') {
966
            foreach ($fieldSetup['items'] as $key => $val) {
967
                if (substr($val[0], 0, 4) === 'LLL:') {
968
                    $value = $this->languageService->sL($val[0]);
969
                } else {
970
                    $value = $val[0];
971
                }
972
                if (GeneralUtility::inList($fieldValue, $val[1]) || $fieldValue == $val[1]) {
973
                    if (!$out) {
974
                        $out = htmlspecialchars($value);
975
                    } else {
976
                        $out .= $splitString . htmlspecialchars($value);
977
                    }
978
                }
979
            }
980
        }
981
        if ($fieldSetup['type'] === 'binary') {
982
            foreach ($fieldSetup['items'] as $Key => $val) {
983
                if (substr($val[0], 0, 4) === 'LLL:') {
984
                    $value = $this->languageService->sL($val[0]);
985
                } else {
986
                    $value = $val[0];
987
                }
988
                if (!$out) {
989
                    $out = htmlspecialchars($value);
990
                } else {
991
                    $out .= $splitString . htmlspecialchars($value);
992
                }
993
            }
994
        }
995
        if ($fieldSetup['type'] === 'relation') {
996
            $dontPrefixFirstTable = 0;
997
            $useTablePrefix = 0;
998
            if ($fieldSetup['items']) {
999
                foreach ($fieldSetup['items'] as $key => $val) {
1000
                    if (substr($val[0], 0, 4) === 'LLL:') {
1001
                        $value = $this->languageService->sL($val[0]);
1002
                    } else {
1003
                        $value = $val[0];
1004
                    }
1005
                    if (GeneralUtility::inList($fieldValue, $value) || $fieldValue == $value) {
1006
                        if (!$out) {
1007
                            $out = htmlspecialchars($value);
1008
                        } else {
1009
                            $out .= $splitString . htmlspecialchars($value);
1010
                        }
1011
                    }
1012
                }
1013
            }
1014
            if (stristr($fieldSetup['allowed'], ',')) {
1015
                $from_table_Arr = explode(',', $fieldSetup['allowed']);
1016
                $useTablePrefix = 1;
1017
                if (!$fieldSetup['prepend_tname']) {
1018
                    $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1019
                    $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1020
                    $statement = $queryBuilder->select($fieldName)->from($table)->execute();
1021
                    while ($row = $statement->fetch()) {
1022
                        if (stristr($row[$fieldName], ',')) {
1023
                            $checkContent = explode(',', $row[$fieldName]);
1024
                            foreach ($checkContent as $singleValue) {
1025
                                if (!stristr($singleValue, '_')) {
1026
                                    $dontPrefixFirstTable = 1;
1027
                                }
1028
                            }
1029
                        } else {
1030
                            $singleValue = $row[$fieldName];
1031
                            if ($singleValue !== '' && !stristr($singleValue, '_')) {
1032
                                $dontPrefixFirstTable = 1;
1033
                            }
1034
                        }
1035
                    }
1036
                }
1037
            } else {
1038
                $from_table_Arr[0] = $fieldSetup['allowed'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$from_table_Arr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $from_table_Arr = array(); before regardless.
Loading history...
1039
            }
1040
            if ($fieldSetup['prepend_tname']) {
1041
                $useTablePrefix = 1;
1042
            }
1043
            if ($fieldSetup['foreign_table']) {
1044
                $from_table_Arr[0] = $fieldSetup['foreign_table'];
1045
            }
1046
            $counter = 0;
1047
            $useSelectLabels = 0;
1048
            $useAltSelectLabels = 0;
1049
            $tablePrefix = '';
1050
            $labelFieldSelect = [];
1051
            foreach ($from_table_Arr as $from_table) {
1052
                if ($useTablePrefix && !$dontPrefixFirstTable && $counter != 1 || $counter == 1) {
1053
                    $tablePrefix = $from_table . '_';
1054
                }
1055
                $counter = 1;
1056
                if (is_array($GLOBALS['TCA'][$from_table])) {
1057
                    $labelField = $GLOBALS['TCA'][$from_table]['ctrl']['label'];
1058
                    $altLabelField = $GLOBALS['TCA'][$from_table]['ctrl']['label_alt'];
1059
                    if ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items']) {
1060
                        $items = $GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items'];
1061
                        foreach ($items as $labelArray) {
1062
                            if (substr($labelArray[0], 0, 4) === 'LLL:') {
1063
                                $labelFieldSelect[$labelArray[1]] = $this->languageService->sL($labelArray[0]);
1064
                            } else {
1065
                                $labelFieldSelect[$labelArray[1]] = $labelArray[0];
1066
                            }
1067
                        }
1068
                        $useSelectLabels = 1;
1069
                    }
1070
                    $altLabelFieldSelect = [];
1071
                    if ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items']) {
1072
                        $items = $GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items'];
1073
                        foreach ($items as $altLabelArray) {
1074
                            if (substr($altLabelArray[0], 0, 4) === 'LLL:') {
1075
                                $altLabelFieldSelect[$altLabelArray[1]] = $this->languageService->sL($altLabelArray[0]);
1076
                            } else {
1077
                                $altLabelFieldSelect[$altLabelArray[1]] = $altLabelArray[0];
1078
                            }
1079
                        }
1080
                        $useAltSelectLabels = 1;
1081
                    }
1082
1083
                    if (!$this->tableArray[$from_table]) {
1084
                        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($from_table);
1085
                        $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1086
                        $selectFields = ['uid', $labelField];
1087
                        if ($altLabelField) {
1088
                            $selectFields[] = $altLabelField;
1089
                        }
1090
                        $queryBuilder->select(...$selectFields)
1091
                            ->from($from_table)
1092
                            ->orderBy('uid');
1093
                        if (!$this->backendUserAuthentication->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
1094
                            $webMounts = $this->backendUserAuthentication->returnWebmounts();
1095
                            $perms_clause = $this->backendUserAuthentication->getPagePermsClause(Permission::PAGE_SHOW);
1096
                            $webMountPageTree = '';
1097
                            $webMountPageTreePrefix = '';
1098
                            foreach ($webMounts as $webMount) {
1099
                                if ($webMountPageTree) {
1100
                                    $webMountPageTreePrefix = ',';
1101
                                }
1102
                                $webMountPageTree .= $webMountPageTreePrefix
1103
                                    . $this->getTreeList($webMount, 999, ($begin = 0), $perms_clause);
1104
                            }
1105
                            if ($from_table === 'pages') {
1106
                                $queryBuilder->where(
1107
                                    QueryHelper::stripLogicalOperatorPrefix($perms_clause),
1108
                                    $queryBuilder->expr()->in(
1109
                                        'uid',
1110
                                        $queryBuilder->createNamedParameter(
1111
                                            GeneralUtility::intExplode(',', $webMountPageTree),
1112
                                            Connection::PARAM_INT_ARRAY
1113
                                        )
1114
                                    )
1115
                                );
1116
                            } else {
1117
                                $queryBuilder->where(
1118
                                    $queryBuilder->expr()->in(
1119
                                        'pid',
1120
                                        $queryBuilder->createNamedParameter(
1121
                                            GeneralUtility::intExplode(',', $webMountPageTree),
1122
                                            Connection::PARAM_INT_ARRAY
1123
                                        )
1124
                                    )
1125
                                );
1126
                            }
1127
                        }
1128
                        $statement = $queryBuilder->execute();
1129
                        $this->tableArray[$from_table] = [];
1130
                        while ($row = $statement->fetch()) {
1131
                            $this->tableArray[$from_table][] = $row;
1132
                        }
1133
                    }
1134
1135
                    foreach ($this->tableArray[$from_table] as $key => $val) {
1136
                        $this->settings['labels_noprefix'] =
1137
                            $this->settings['labels_noprefix'] == 1
1138
                                ? 'on'
1139
                                : $this->settings['labels_noprefix'];
1140
                        $prefixString =
1141
                            $this->settings['labels_noprefix'] === 'on'
1142
                                ? ''
1143
                                : ' [' . $tablePrefix . $val['uid'] . '] ';
1144
                        if (GeneralUtility::inList($fieldValue, $tablePrefix . $val['uid'])
1145
                            || $fieldValue == $tablePrefix . $val['uid']) {
1146
                            if ($useSelectLabels) {
1147
                                if (!$out) {
1148
                                    $out = htmlspecialchars($prefixString . $labelFieldSelect[$val[$labelField]]);
1149
                                } else {
1150
                                    $out .= $splitString . htmlspecialchars(
1151
                                        $prefixString . $labelFieldSelect[$val[$labelField]]
1152
                                    );
1153
                                }
1154
                            } elseif ($val[$labelField]) {
1155
                                if (!$out) {
1156
                                    $out = htmlspecialchars($prefixString . $val[$labelField]);
1157
                                } else {
1158
                                    $out .= $splitString . htmlspecialchars(
1159
                                        $prefixString . $val[$labelField]
1160
                                    );
1161
                                }
1162
                            } elseif ($useAltSelectLabels) {
1163
                                if (!$out) {
1164
                                    $out = htmlspecialchars($prefixString . $altLabelFieldSelect[$val[$altLabelField]]);
1165
                                } else {
1166
                                    $out .= $splitString . htmlspecialchars(
1167
                                        $prefixString . $altLabelFieldSelect[$val[$altLabelField]]
1168
                                    );
1169
                                }
1170
                            } else {
1171
                                if (!$out) {
1172
                                    $out = htmlspecialchars($prefixString . $val[$altLabelField]);
1173
                                } else {
1174
                                    $out .= $splitString . htmlspecialchars(($prefixString . $val[$altLabelField]));
1175
                                }
1176
                            }
1177
                        }
1178
                    }
1179
                }
1180
            }
1181
        }
1182
        return $out;
1183
    }
1184
1185
    /**
1186
     * Render table header
1187
     *
1188
     * @param array $row Table columns
1189
     * @param array $conf Table TCA
1190
     * @param string $table Table name
1191
     * @return string HTML of table header
1192
     */
1193
    public function resultRowTitles($row, $conf, $table)
0 ignored issues
show
Unused Code introduced by
The parameter $table is not used and could be removed. ( Ignorable by Annotation )

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

1193
    public function resultRowTitles($row, $conf, /** @scrutinizer ignore-unused */ $table)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1194
    {
1195
        $tableHeader = [];
1196
        // Start header row
1197
        $tableHeader[] = '<thead><tr>';
1198
        // Iterate over given columns
1199
        foreach ($row as $fieldName => $fieldValue) {
1200
            if (GeneralUtility::inList($this->settings['queryFields'], $fieldName)
1201
                || !$this->settings['queryFields']
1202
                && $fieldName !== 'pid'
1203
                && $fieldName !== 'deleted'
1204
            ) {
1205
                if ($this->settings['search_result_labels']) {
1206
                    $title = htmlspecialchars($this->languageService->sL($conf['columns'][$fieldName]['label']
1207
                        ? $conf['columns'][$fieldName]['label']
1208
                        : $fieldName));
1209
                } else {
1210
                    $title = htmlspecialchars($this->languageService->sL($fieldName));
1211
                }
1212
                $tableHeader[] = '<th>' . $title . '</th>';
1213
            }
1214
        }
1215
        // Add empty icon column
1216
        $tableHeader[] = '<th></th>';
1217
        // Close header row
1218
        $tableHeader[] = '</tr></thead>';
1219
        return implode(LF, $tableHeader);
1220
    }
1221
1222
    /**
1223
     * CSV row titles
1224
     *
1225
     * @param array $row
1226
     * @param array $conf
1227
     * @param mixed $table Not used
1228
     * @return string
1229
     */
1230
    public function csvRowTitles($row, $conf, $table)
0 ignored issues
show
Unused Code introduced by
The parameter $table is not used and could be removed. ( Ignorable by Annotation )

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

1230
    public function csvRowTitles($row, $conf, /** @scrutinizer ignore-unused */ $table)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1231
    {
1232
        $out = '';
1233
        foreach ($row as $fieldName => $fieldValue) {
1234
            if (GeneralUtility::inList($this->settings['queryFields'], $fieldName)
1235
                || !$this->settings['queryFields'] && $fieldName !== 'pid') {
1236
                if (!$out) {
1237
                    if ($this->settings['search_result_labels']) {
1238
                        $out = htmlspecialchars($this->languageService->sL($conf['columns'][$fieldName]['label']
1239
                            ? $conf['columns'][$fieldName]['label']
1240
                            : $fieldName));
1241
                    } else {
1242
                        $out = htmlspecialchars($this->languageService->sL($fieldName));
1243
                    }
1244
                } else {
1245
                    if ($this->settings['search_result_labels']) {
1246
                        $out .= ',' . htmlspecialchars($this->languageService->sL(($conf['columns'][$fieldName]['label']
1247
                            ? $conf['columns'][$fieldName]['label']
1248
                            : $fieldName)));
1249
                    } else {
1250
                        $out .= ',' . htmlspecialchars($this->languageService->sL($fieldName));
1251
                    }
1252
                }
1253
            }
1254
        }
1255
        return $out;
1256
    }
1257
1258
    /**
1259
     * Sets the current name of the input form.
1260
     *
1261
     * @param string $formName The name of the form.
1262
     */
1263
    public function setFormName($formName)
1264
    {
1265
        $this->formName = trim($formName);
1266
    }
1267
}
1268