a3c4345f9f30dfb8808c319f61b7ebdd88370166
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / RecordList / AbstractDatabaseRecordList.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\RecordList;
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 TYPO3\CMS\Backend\RecordList\AbstractRecordList;
18 use TYPO3\CMS\Backend\Routing\UriBuilder;
19 use TYPO3\CMS\Backend\Tree\View\PageTreeView;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\Cache\CacheManager;
23 use TYPO3\CMS\Core\Database\Connection;
24 use TYPO3\CMS\Core\Database\ConnectionPool;
25 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
26 use TYPO3\CMS\Core\Database\Query\QueryHelper;
27 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
28 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
29 use TYPO3\CMS\Core\Imaging\Icon;
30 use TYPO3\CMS\Core\Imaging\IconFactory;
31 use TYPO3\CMS\Core\Log\LogManager;
32 use TYPO3\CMS\Core\Service\DependencyOrderingService;
33 use TYPO3\CMS\Core\Type\Bitmask\Permission;
34 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36 use TYPO3\CMS\Core\Utility\HttpUtility;
37 use TYPO3\CMS\Core\Utility\MathUtility;
38
39 /**
40 * Child class for rendering of Web > List (not the final class)
41 * Shared between Web>List and Web>Page
42 * @see \TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
43 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
44 */
45 class AbstractDatabaseRecordList extends AbstractRecordList
46 {
47 /**
48 * Specify a list of tables which are the only ones allowed to be displayed.
49 *
50 * @var string
51 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
52 */
53 public $tableList = '';
54
55 /**
56 * Return URL
57 *
58 * @var string
59 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
60 */
61 public $returnUrl = '';
62
63 /**
64 * Thumbnails on records containing files (pictures)
65 *
66 * @var bool
67 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
68 */
69 public $thumbs = 0;
70
71 /**
72 * default Max items shown per table in "multi-table mode", may be overridden by tables.php
73 *
74 * @var int
75 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
76 */
77 public $itemsLimitPerTable = 20;
78
79 /**
80 * default Max items shown per table in "single-table mode", may be overridden by tables.php
81 *
82 * @var int
83 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
84 */
85 public $itemsLimitSingleTable = 100;
86
87 /**
88 * Current script name
89 *
90 * @var string
91 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
92 */
93 public $script = 'index.php';
94
95 /**
96 * Indicates if all available fields for a user should be selected or not.
97 *
98 * @var int
99 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
100 */
101 public $allFields = 0;
102
103 /**
104 * Whether to show localization view or not
105 *
106 * @var bool
107 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
108 */
109 public $localizationView = false;
110
111 /**
112 * If set, csvList is outputted.
113 *
114 * @var bool
115 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
116 */
117 public $csvOutput = false;
118
119 /**
120 * Field, to sort list by
121 *
122 * @var string
123 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
124 */
125 public $sortField;
126
127 /**
128 * Field, indicating to sort in reverse order.
129 *
130 * @var bool
131 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
132 */
133 public $sortRev;
134
135 /**
136 * Containing which fields to display in extended mode
137 *
138 * @var string[]
139 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
140 */
141 public $displayFields;
142
143 /**
144 * String, can contain the field name from a table which must have duplicate values marked.
145 *
146 * @var string
147 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
148 */
149 public $duplicateField;
150
151 /**
152 * Page id
153 *
154 * @var int
155 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
156 */
157 public $id;
158
159 /**
160 * Tablename if single-table mode
161 *
162 * @var string
163 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
164 */
165 public $table = '';
166
167 /**
168 * If TRUE, records are listed only if a specific table is selected.
169 *
170 * @var bool
171 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
172 */
173 public $listOnlyInSingleTableMode = false;
174
175 /**
176 * Pointer for browsing list
177 *
178 * @var int
179 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
180 */
181 public $firstElementNumber = 0;
182
183 /**
184 * Search string
185 *
186 * @var string
187 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
188 */
189 public $searchString = '';
190
191 /**
192 * Levels to search down.
193 *
194 * @var int
195 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
196 */
197 public $searchLevels = '';
198
199 /**
200 * Number of records to show
201 *
202 * @var int
203 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
204 */
205 public $showLimit = 0;
206
207 /**
208 * Page select permissions
209 *
210 * @var string
211 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
212 */
213 public $perms_clause = '';
214
215 /**
216 * Some permissions...
217 *
218 * @var int
219 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
220 */
221 public $calcPerms = 0;
222
223 /**
224 * Mode for what happens when a user clicks the title of a record.
225 *
226 * @var string
227 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
228 */
229 public $clickTitleMode = '';
230
231 /**
232 * Shared module configuration, used by localization features
233 *
234 * @var array
235 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
236 */
237 public $modSharedTSconfig = [];
238
239 /**
240 * Loaded with page record with version overlay if any.
241 *
242 * @var string[]
243 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
244 */
245 public $pageRecord = [];
246
247 /**
248 * Tables which should not get listed
249 *
250 * @var string
251 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
252 */
253 public $hideTables = '';
254
255 /**
256 * Tables which should not list their translations
257 *
258 * @var string
259 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
260 */
261 public $hideTranslations = '';
262
263 /**
264 * TSconfig which overwrites TCA-Settings
265 *
266 * @var mixed[][]
267 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
268 */
269 public $tableTSconfigOverTCA = [];
270
271 /**
272 * Array of collapsed / uncollapsed tables in multi table view
273 *
274 * @var int[][]
275 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
276 */
277 public $tablesCollapsed = [];
278
279 /**
280 * JavaScript code accumulation
281 *
282 * @var string
283 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
284 */
285 public $JScode = '';
286
287 /**
288 * HTML output
289 *
290 * @var string
291 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
292 */
293 public $HTMLcode = '';
294
295 /**
296 * "LIMIT " in SQL...
297 *
298 * @var int
299 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
300 */
301 public $iLimit = 0;
302
303 /**
304 * Counting the elements no matter what...
305 *
306 * @var int
307 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
308 */
309 public $eCounter = 0;
310
311 /**
312 * Set to the total number of items for a table when selecting.
313 *
314 * @var string
315 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
316 */
317 public $totalItems = '';
318
319 /**
320 * Cache for record path
321 *
322 * @var mixed[]
323 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
324 */
325 public $recPath_cache = [];
326
327 /**
328 * Fields to display for the current table
329 *
330 * @var string[]
331 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
332 */
333 public $setFields = [];
334
335 /**
336 * Used for tracking next/prev uids
337 *
338 * @var int[][]
339 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
340 */
341 public $currentTable = [];
342
343 /**
344 * Used for tracking duplicate values of fields
345 *
346 * @var string[]
347 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
348 */
349 public $duplicateStack = [];
350
351 /**
352 * @var array[] Module configuration
353 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
354 */
355 public $modTSconfig;
356
357 /**
358 * Override/add urlparameters in listUrl() method
359 * @var string[]
360 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
361 */
362 protected $overrideUrlParameters = [];
363
364 /**
365 * Override the page ids taken into account by getPageIdConstraint()
366 *
367 * @var array
368 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
369 */
370 protected $overridePageIdList = [];
371
372 /**
373 * Array with before/after setting for tables
374 * Structure:
375 * 'tableName' => [
376 * 'before' => ['A', ...]
377 * 'after' => []
378 * ]
379 * @var array[]
380 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
381 */
382 protected $tableDisplayOrder = [];
383
384 /**
385 * Initializes the list generation
386 *
387 * @param int $id Page id for which the list is rendered. Must be >= 0
388 * @param string $table Tablename - if extended mode where only one table is listed at a time.
389 * @param int $pointer Browsing pointer.
390 * @param string $search Search word, if any
391 * @param int $levels Number of levels to search down the page tree
392 * @param int $showLimit Limit of records to be listed.
393 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
394 */
395 public function start($id, $table, $pointer, $search = '', $levels = 0, $showLimit = 0)
396 {
397 $backendUser = $this->getBackendUserAuthentication();
398 // Setting internal variables:
399 // sets the parent id
400 $this->id = (int)$id;
401 if ($GLOBALS['TCA'][$table]) {
402 // Setting single table mode, if table exists:
403 $this->table = $table;
404 }
405 $this->firstElementNumber = $pointer;
406 $this->searchString = trim($search);
407 $this->searchLevels = (int)$levels;
408 $this->showLimit = MathUtility::forceIntegerInRange($showLimit, 0, 10000);
409 // Setting GPvars:
410 $this->csvOutput = (bool)GeneralUtility::_GP('csv');
411 $this->sortField = GeneralUtility::_GP('sortField');
412 $this->sortRev = GeneralUtility::_GP('sortRev');
413 $this->displayFields = GeneralUtility::_GP('displayFields');
414 $this->duplicateField = GeneralUtility::_GP('duplicateField');
415 if (GeneralUtility::_GP('justLocalized')) {
416 $this->localizationRedirect(GeneralUtility::_GP('justLocalized'));
417 }
418 // Init dynamic vars:
419 $this->counter = 0;
420 $this->JScode = '';
421 $this->HTMLcode = '';
422 // Limits
423 if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
424 $this->itemsLimitPerTable = MathUtility::forceIntegerInRange(
425 (int)$this->modTSconfig['properties']['itemsLimitPerTable'],
426 1,
427 10000
428 );
429 }
430 if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
431 $this->itemsLimitSingleTable = MathUtility::forceIntegerInRange(
432 (int)$this->modTSconfig['properties']['itemsLimitSingleTable'],
433 1,
434 10000
435 );
436 }
437
438 // $table might be NULL at this point in the code. As the expressionBuilder
439 // is used to limit returned records based on the page permissions and the
440 // uid field of the pages it can hardcoded to work on the pages table.
441 $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
442 ->getQueryBuilderForTable('pages')
443 ->expr();
444 $permsClause = $expressionBuilder->andX($backendUser->getPagePermsClause(1));
445 // This will hide records from display - it has nothing to do with user rights!!
446 if ($pidList = $backendUser->getTSConfigVal('options.hideRecords.pages')) {
447 $pidList = GeneralUtility::intExplode(',', $pidList, true);
448 if (!empty($pidList)) {
449 $permsClause->add($expressionBuilder->notIn('pages.uid', $pidList));
450 }
451 }
452 $this->perms_clause = (string)$permsClause;
453
454 // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
455 $this->tablesCollapsed = is_array($backendUser->uc['moduleData']['list'])
456 ? $backendUser->uc['moduleData']['list']
457 : [];
458 $collapseOverride = GeneralUtility::_GP('collapse');
459 if (is_array($collapseOverride)) {
460 foreach ($collapseOverride as $collapseTable => $collapseValue) {
461 if (is_array($GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) {
462 $this->tablesCollapsed[$collapseTable] = $collapseValue;
463 }
464 }
465 // Save modified user uc
466 $backendUser->uc['moduleData']['list'] = $this->tablesCollapsed;
467 $backendUser->writeUC($backendUser->uc);
468 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
469 if ($returnUrl !== '') {
470 HttpUtility::redirect($returnUrl);
471 }
472 }
473
474 // Initialize languages:
475 if ($this->localizationView) {
476 $this->initializeLanguages();
477 }
478 }
479
480 /**
481 * Traverses the table(s) to be listed and renders the output code for each:
482 * The HTML is accumulated in $this->HTMLcode
483 * Finishes off with a stopper-gif
484 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
485 */
486 public function generateList()
487 {
488 // Set page record in header
489 $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id);
490 $hideTablesArray = GeneralUtility::trimExplode(',', $this->hideTables);
491
492 $backendUser = $this->getBackendUserAuthentication();
493
494 // pre-process tables and add sorting instructions
495 $tableNames = array_flip(array_keys($GLOBALS['TCA']));
496 foreach ($tableNames as $tableName => &$config) {
497 $hideTable = false;
498
499 // Checking if the table should be rendered:
500 // Checks that we see only permitted/requested tables:
501 if ($this->table && $tableName !== $this->table
502 || $this->tableList && !GeneralUtility::inList($this->tableList, $tableName)
503 || !$backendUser->check('tables_select', $tableName)
504 ) {
505 $hideTable = true;
506 }
507
508 if (!$hideTable) {
509 // Don't show table if hidden by TCA ctrl section
510 // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
511 $hideTable = $hideTable
512 || !empty($GLOBALS['TCA'][$tableName]['ctrl']['hideTable'])
513 || in_array($tableName, $hideTablesArray, true)
514 || in_array('*', $hideTablesArray, true);
515 // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
516 if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
517 $hideTable = (bool)$this->tableTSconfigOverTCA[$tableName . '.']['hideTable'];
518 }
519 }
520 if ($hideTable) {
521 unset($tableNames[$tableName]);
522 } else {
523 if (isset($this->tableDisplayOrder[$tableName])) {
524 // Copy display order information
525 $tableNames[$tableName] = $this->tableDisplayOrder[$tableName];
526 } else {
527 $tableNames[$tableName] = [];
528 }
529 }
530 }
531 unset($config);
532
533 $orderedTableNames = GeneralUtility::makeInstance(DependencyOrderingService::class)
534 ->orderByDependencies($tableNames);
535
536 foreach ($orderedTableNames as $tableName => $_) {
537 // check if we are in single- or multi-table mode
538 if ($this->table) {
539 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'])
540 ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']
541 : $this->itemsLimitSingleTable;
542 } else {
543 // if there are no records in table continue current foreach
544 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
545 ->getQueryBuilderForTable($tableName);
546 $queryBuilder->getRestrictions()
547 ->removeAll()
548 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
549 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
550 $queryBuilder = $this->addPageIdConstraint($tableName, $queryBuilder);
551 $firstRow = $queryBuilder->select('uid')
552 ->from($tableName)
553 ->execute()
554 ->fetch();
555 if (!is_array($firstRow)) {
556 continue;
557 }
558 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'])
559 ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']
560 : $this->itemsLimitPerTable;
561 }
562 if ($this->showLimit) {
563 $this->iLimit = $this->showLimit;
564 }
565 // Setting fields to select:
566 if ($this->allFields) {
567 $fields = $this->makeFieldList($tableName);
568 $fields[] = 'tstamp';
569 $fields[] = 'crdate';
570 $fields[] = '_PATH_';
571 $fields[] = '_CONTROL_';
572 if (is_array($this->setFields[$tableName])) {
573 $fields = array_intersect($fields, $this->setFields[$tableName]);
574 } else {
575 $fields = [];
576 }
577 } else {
578 $fields = [];
579 }
580
581 // Finally, render the list:
582 $this->HTMLcode .= $this->getTable($tableName, $this->id, implode(',', $fields));
583 }
584 }
585
586 /**
587 * To be implemented in extending classes.
588 *
589 * @param string $tableName
590 * @param int $id
591 * @param string $fields List of fields to show in the listing. Pseudo fields will be added including the record header.
592 * @return string HTML code
593 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
594 */
595 public function getTable($tableName, $id, $fields = '')
596 {
597 return '';
598 }
599
600 /**
601 * Creates the search box
602 *
603 * @param bool $formFields If TRUE, the search box is wrapped in its own form-tags
604 * @return string HTML for the search box
605 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
606 */
607 public function getSearchBox($formFields = true)
608 {
609 /** @var $iconFactory IconFactory */
610 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
611 $lang = $this->getLanguageService();
612 // Setting form-elements, if applicable:
613 $formElements = ['', ''];
614 if ($formFields) {
615 $formElements = ['<form action="' . htmlspecialchars($this->listURL('', '-1', 'firstElementNumber,search_field')) . '" method="post">', '</form>'];
616 }
617 // Make level selector:
618 $opt = [];
619
620 // "New" generation of search levels ... based on TS config
621 $config = BackendUtility::getPagesTSconfig($this->id);
622 $searchLevelsFromTSconfig = $config['mod.']['web_list.']['searchLevel.']['items.'];
623 $searchLevelItems = [];
624
625 // get translated labels for search levels from pagets
626 foreach ($searchLevelsFromTSconfig as $keySearchLevel => $labelConfigured) {
627 $label = $lang->sL('LLL:' . $labelConfigured);
628 if ($label === '') {
629 $label = $labelConfigured;
630 }
631 $searchLevelItems[$keySearchLevel] = $label;
632 }
633
634 foreach ($searchLevelItems as $kv => $label) {
635 $opt[] = '<option value="' . $kv . '"' . ($kv === $this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
636 }
637 $lMenu = '<select class="form-control" name="search_levels" title="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.search_levels')) . '" id="search_levels">' . implode('', $opt) . '</select>';
638 // Table with the search box:
639 $content = '<div class="db_list-searchbox-form db_list-searchbox-toolbar module-docheader-bar module-docheader-bar-search t3js-module-docheader-bar t3js-module-docheader-bar-search" id="db_list-searchbox-toolbar" style="display: ' . ($this->searchString == '' ? 'none' : 'block') . ';">
640 ' . $formElements[0] . '
641 <div id="typo3-dblist-search">
642 <div class="panel panel-default">
643 <div class="panel-body">
644 <div class="row">
645 <div class="form-group col-xs-12">
646 <label for="search_field">' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.label.searchString')) . ': </label>
647 <input class="form-control" type="search" placeholder="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.enterSearchString')) . '" title="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.searchString')) . '" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '" />
648 </div>
649 <div class="form-group col-xs-12 col-sm-6">
650 <label for="search_levels">' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.label.search_levels')) . ': </label>
651 ' . $lMenu . '
652 </div>
653 <div class="form-group col-xs-12 col-sm-6">
654 <label for="showLimit">' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.label.limit')) . ': </label>
655 <input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.limit')) . '" name="showLimit" id="showLimit" value="' . htmlspecialchars(($this->showLimit ? $this->showLimit : '')) . '" />
656 </div>
657 <div class="form-group col-xs-12">
658 <div class="form-control-wrap">
659 <button type="submit" class="btn btn-default" name="search" title="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.title.search')) . '">
660 ' . $iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.search')) . '
661 </button>
662 </div>
663 </div>
664 </div>
665 </div>
666 </div>
667 </div>
668 ' . $formElements[1] . '</div>';
669 return $content;
670 }
671
672 /******************************
673 *
674 * Various helper functions
675 *
676 ******************************/
677 /**
678 * Setting the field names to display in extended list.
679 * Sets the internal variable $this->setFields
680 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
681 */
682 public function setDispFields()
683 {
684 $backendUser = $this->getBackendUserAuthentication();
685 // Getting from session:
686 $dispFields = $backendUser->getModuleData('list/displayFields');
687 // If fields has been inputted, then set those as the value and push it to session variable:
688 if (is_array($this->displayFields)) {
689 reset($this->displayFields);
690 $tKey = key($this->displayFields);
691 $dispFields[$tKey] = $this->displayFields[$tKey];
692 $backendUser->pushModuleData('list/displayFields', $dispFields);
693 }
694 // Setting result:
695 $this->setFields = $dispFields;
696 }
697
698 /**
699 * Create thumbnail code for record/field
700 *
701 * @param mixed[] $row Record array
702 * @param string $table Table (record is from)
703 * @param string $field Field name for which thumbnail are to be rendered.
704 * @return string HTML for thumbnails, if any.
705 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
706 */
707 public function thumbCode($row, $table, $field)
708 {
709 return BackendUtility::thumbCode($row, $table, $field);
710 }
711
712 /**
713 * Returns a QueryBuilder configured to select $fields from $table where the pid is restricted
714 * depending on the current searchlevel setting.
715 *
716 * @param string $table Table name
717 * @param int $pageId Page id Only used to build the search constraints, getPageIdConstraint() used for restrictions
718 * @param string[] $additionalConstraints Additional part for where clause
719 * @param string[] $fields Field list to select, * for all
720 * @return \TYPO3\CMS\Core\Database\Query\QueryBuilder
721 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
722 */
723 public function getQueryBuilder(
724 string $table,
725 int $pageId,
726 array $additionalConstraints = [],
727 array $fields = ['*']
728 ): QueryBuilder {
729 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
730 ->getQueryBuilderForTable($table);
731 $queryBuilder->getRestrictions()
732 ->removeAll()
733 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
734 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
735 $queryBuilder
736 ->select(...$fields)
737 ->from($table);
738
739 if (!empty($additionalConstraints)) {
740 $queryBuilder->andWhere(...$additionalConstraints);
741 }
742
743 $queryBuilder = $this->prepareQueryBuilder($table, $pageId, $fields, $additionalConstraints, $queryBuilder);
744
745 return $queryBuilder;
746 }
747
748 /**
749 * Return the modified QueryBuilder object ($queryBuilder) which will be
750 * used to select the records from a table $table with pid = $this->pidList
751 *
752 * @param string $table Table name
753 * @param int $pageId Page id Only used to build the search constraints, $this->pidList is used for restrictions
754 * @param string[] $fieldList List of fields to select from the table
755 * @param string[] $additionalConstraints Additional part for where clause
756 * @param QueryBuilder $queryBuilder
757 * @paran bool $addSorting
758 * @return QueryBuilder
759 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
760 */
761 protected function prepareQueryBuilder(
762 string $table,
763 int $pageId,
764 array $fieldList = ['*'],
765 array $additionalConstraints = [],
766 QueryBuilder $queryBuilder,
767 bool $addSorting = true
768 ): QueryBuilder {
769 $parameters = [
770 'table' => $table,
771 'fields' => $fieldList,
772 'groupBy' => null,
773 'orderBy' => null,
774 'firstResult' => $this->firstElementNumber ?: null,
775 'maxResults' => $this->iLimit ?: null
776 ];
777
778 if ($this->iLimit !== null) {
779 $queryBuilder->setMaxResults($this->iLimit);
780 }
781
782 if ($addSorting) {
783 if ($this->sortField && in_array($this->sortField, $this->makeFieldList($table, 1))) {
784 $queryBuilder->orderBy($this->sortField, $this->sortRev ? 'DESC' : 'ASC');
785 } else {
786 $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ?: $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
787 $orderBys = QueryHelper::parseOrderBy((string)$orderBy);
788 foreach ($orderBys as $orderBy) {
789 $queryBuilder->orderBy($orderBy[0], $orderBy[1]);
790 }
791 }
792 }
793
794 // Build the query constraints
795 $queryBuilder = $this->addPageIdConstraint($table, $queryBuilder);
796 $searchWhere = $this->makeSearchString($table, $pageId);
797 if (!empty($searchWhere)) {
798 $queryBuilder->andWhere($searchWhere);
799 }
800
801 // Filtering on displayable pages (permissions):
802 if ($table === 'pages' && $this->perms_clause) {
803 $queryBuilder->andWhere($this->perms_clause);
804 }
805
806 // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
807 if (
808 $table !== 'pages_language_overlay'
809 && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'])
810 && (GeneralUtility::inList($this->hideTranslations, $table) || $this->hideTranslations === '*')
811 ) {
812 $queryBuilder->andWhere($queryBuilder->expr()->eq(
813 $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'],
814 0
815 ));
816 }
817
818 $hookName = DatabaseRecordList::class;
819 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['buildQueryParameters'])) {
820 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['buildQueryParameters'] as $className) {
821 $hookObject = GeneralUtility::makeInstance($className);
822 if (method_exists($hookObject, 'buildQueryParametersPostProcess')) {
823 $hookObject->buildQueryParametersPostProcess(
824 $parameters,
825 $table,
826 $pageId,
827 $additionalConstraints,
828 $fieldList,
829 $this,
830 $queryBuilder
831 );
832 }
833 }
834 }
835
836 // array_unique / array_filter used to eliminate empty and duplicate constraints
837 // the array keys are eliminated by this as well to facilitate argument unpacking
838 // when used with the querybuilder.
839 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10
840 if (!empty($parameters['where'])) {
841 $parameters['where'] = array_unique(array_filter(array_values($parameters['where'])));
842 }
843 if (!empty($parameters['where'])) {
844 $this->logDeprecation('where');
845 $queryBuilder->where(...$parameters['where']);
846 }
847 if (!empty($parameters['orderBy'])) {
848 $this->logDeprecation('orderBy');
849 foreach ($parameters['orderBy'] as $fieldNameAndSorting) {
850 list($fieldName, $sorting) = $fieldNameAndSorting;
851 $queryBuilder->addOrderBy($fieldName, $sorting);
852 }
853 }
854 if (!empty($parameters['firstResult'])) {
855 $this->logDeprecation('firstResult');
856 $queryBuilder->setFirstResult((int)$parameters['firstResult']);
857 }
858 if (!empty($parameters['maxResults']) && $parameters['maxResults'] !== $this->iLimit) {
859 $this->logDeprecation('maxResults');
860 $queryBuilder->setMaxResults((int)$parameters['maxResults']);
861 }
862 if (!empty($parameters['groupBy'])) {
863 $this->logDeprecation('groupBy');
864 $queryBuilder->groupBy($parameters['groupBy']);
865 }
866
867 return $queryBuilder;
868 }
869
870 /**
871 * Executed a query to set $this->totalItems to the number of total
872 * items, eg. for pagination
873 *
874 * @param string $table Table name
875 * @param int $pageId Only used to build the search constraints, $this->pidList is used for restrictions
876 * @param array $constraints Additional constraints for where clause
877 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
878 */
879 public function setTotalItems(string $table, int $pageId, array $constraints)
880 {
881 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
882 ->getQueryBuilderForTable($table);
883
884 $queryBuilder->getRestrictions()
885 ->removeAll()
886 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
887 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
888 $queryBuilder
889 ->from($table);
890
891 if (!empty($constraints)) {
892 $queryBuilder->andWhere(...$constraints);
893 }
894
895 $queryBuilder = $this->prepareQueryBuilder($table, $pageId, ['*'], $constraints, $queryBuilder, false);
896 // Reset limit and offset for full count query
897 $queryBuilder->setFirstResult(0);
898 $queryBuilder->setMaxResults(1);
899
900 $this->totalItems = (int)$queryBuilder->count('*')
901 ->execute()
902 ->fetchColumn();
903 }
904
905 /**
906 * Creates part of query for searching after a word ($this->searchString)
907 * fields in input table.
908 *
909 * @param string $table Table, in which the fields are being searched.
910 * @param int $currentPid Page id for the possible search limit. -1 only if called from an old XCLASS.
911 * @return string Returns part of WHERE-clause for searching, if applicable.
912 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
913 */
914 public function makeSearchString($table, $currentPid = -1)
915 {
916 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
917 $expressionBuilder = $queryBuilder->expr();
918 $constraints = [];
919 $currentPid = (int)$currentPid;
920 $tablePidField = $table === 'pages' ? 'uid' : 'pid';
921 // Make query, only if table is valid and a search string is actually defined:
922 if (empty($this->searchString)) {
923 return '';
924 }
925
926 $searchableFields = $this->getSearchFields($table);
927 if (empty($searchableFields)) {
928 return '';
929 }
930 if (MathUtility::canBeInterpretedAsInteger($this->searchString)) {
931 $constraints[] = $expressionBuilder->eq('uid', (int)$this->searchString);
932 foreach ($searchableFields as $fieldName) {
933 if (!isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
934 continue;
935 }
936 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
937 $fieldType = $fieldConfig['type'];
938 $evalRules = $fieldConfig['eval'] ?: '';
939 if ($fieldType === 'input' && $evalRules && GeneralUtility::inList($evalRules, 'int')) {
940 if (is_array($fieldConfig['search'])
941 && in_array('pidonly', $fieldConfig['search'], true)
942 && $currentPid > 0
943 ) {
944 $constraints[] = $expressionBuilder->andX(
945 $expressionBuilder->eq($fieldName, (int)$this->searchString),
946 $expressionBuilder->eq($tablePidField, (int)$currentPid)
947 );
948 }
949 } elseif ($fieldType === 'text'
950 || $fieldType === 'flex'
951 || ($fieldType === 'input' && (!$evalRules || !preg_match('/date|time|int/', $evalRules)))
952 ) {
953 $constraints[] = $expressionBuilder->like(
954 $fieldName,
955 $queryBuilder->quote('%' . (int)$this->searchString . '%')
956 );
957 }
958 }
959 } else {
960 $like = $queryBuilder->quote('%' . $queryBuilder->escapeLikeWildcards($this->searchString) . '%');
961 foreach ($searchableFields as $fieldName) {
962 if (!isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
963 continue;
964 }
965 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
966 $fieldType = $fieldConfig['type'];
967 $evalRules = $fieldConfig['eval'] ?: '';
968 $searchConstraint = $expressionBuilder->andX(
969 $expressionBuilder->comparison(
970 'LOWER(' . $queryBuilder->quoteIdentifier($fieldName) . ')',
971 'LIKE',
972 'LOWER(' . $like . ')'
973 )
974 );
975 if (is_array($fieldConfig['search'])) {
976 $searchConfig = $fieldConfig['search'];
977 if (in_array('case', $searchConfig)) {
978 // Replace case insensitive default constraint
979 $searchConstraint = $expressionBuilder->andX($expressionBuilder->like($fieldName, $like));
980 }
981 if (in_array('pidonly', $searchConfig) && $currentPid > 0) {
982 $searchConstraint->add($expressionBuilder->eq($tablePidField, (int)$currentPid));
983 }
984 if ($searchConfig['andWhere']) {
985 $searchConstraint->add(
986 QueryHelper::stripLogicalOperatorPrefix($fieldConfig['search']['andWhere'])
987 );
988 }
989 }
990 if ($fieldType === 'text'
991 || $fieldType === 'flex'
992 || $fieldType === 'input' && (!$evalRules || !preg_match('/date|time|int/', $evalRules))
993 ) {
994 if ($searchConstraint->count() !== 0) {
995 $constraints[] = $searchConstraint;
996 }
997 }
998 }
999 }
1000 // If no search field conditions have been build ensure no results are returned
1001 if (empty($constraints)) {
1002 return '0=1';
1003 }
1004
1005 return $expressionBuilder->orX(...$constraints);
1006 }
1007
1008 /**
1009 * Fetches a list of fields to use in the Backend search for the given table.
1010 *
1011 * @param string $tableName
1012 * @return string[]
1013 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1014 */
1015 protected function getSearchFields($tableName)
1016 {
1017 $fieldArray = [];
1018 $fieldListWasSet = false;
1019 // Get fields from ctrl section of TCA first
1020 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
1021 $fieldArray = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], true);
1022 $fieldListWasSet = true;
1023 }
1024 // Call hook to add or change the list
1025 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
1026 $hookParameters = [
1027 'tableHasSearchConfiguration' => $fieldListWasSet,
1028 'tableName' => $tableName,
1029 'searchFields' => &$fieldArray,
1030 'searchString' => $this->searchString
1031 ];
1032 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
1033 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
1034 }
1035 }
1036 return $fieldArray;
1037 }
1038
1039 /**
1040 * Returns the title (based on $code) of a table ($table) with the proper link around. For headers over tables.
1041 * The link will cause the display of all extended mode or not for the table.
1042 *
1043 * @param string $table Table name
1044 * @param string $code Table label
1045 * @return string The linked table label
1046 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1047 */
1048 public function linkWrapTable($table, $code)
1049 {
1050 if ($this->table !== $table) {
1051 return '<a href="' . htmlspecialchars($this->listURL('', $table, 'firstElementNumber')) . '">' . $code . '</a>';
1052 }
1053 return '<a href="' . htmlspecialchars($this->listURL('', '', 'sortField,sortRev,table,firstElementNumber')) . '">' . $code . '</a>';
1054 }
1055
1056 /**
1057 * Returns the title (based on $code) of a record (from table $table) with the proper link around (that is for 'pages'-records a link to the level of that record...)
1058 *
1059 * @param string $table Table name
1060 * @param int $uid Item uid
1061 * @param string $code Item title (not htmlspecialchars()'ed yet)
1062 * @param mixed[] $row Item row
1063 * @return string The item title. Ready for HTML output (is htmlspecialchars()'ed)
1064 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1065 */
1066 public function linkWrapItems($table, $uid, $code, $row)
1067 {
1068 $lang = $this->getLanguageService();
1069 $origCode = $code;
1070 // If the title is blank, make a "no title" label:
1071 if ((string)$code === '') {
1072 $code = '<i>[' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.no_title')) . ']</i> - '
1073 . htmlspecialchars(BackendUtility::getRecordTitle($table, $row));
1074 } else {
1075 $code = htmlspecialchars($code, ENT_QUOTES, 'UTF-8', false);
1076 if ($code != htmlspecialchars($origCode)) {
1077 $code = '<span title="' . htmlspecialchars($origCode, ENT_QUOTES, 'UTF-8', false) . '">' . $code . '</span>';
1078 }
1079 }
1080 switch ((string)$this->clickTitleMode) {
1081 case 'edit':
1082 // If the listed table is 'pages' we have to request the permission settings for each page:
1083 if ($table === 'pages') {
1084 $localCalcPerms = $this->getBackendUserAuthentication()->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
1085 $permsEdit = $localCalcPerms & Permission::PAGE_EDIT;
1086 } else {
1087 $permsEdit = $this->calcPerms & Permission::CONTENT_EDIT;
1088 }
1089 // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
1090 if ($permsEdit) {
1091 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
1092 $code = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', -1)) . '" title="' . htmlspecialchars($lang->getLL('edit')) . '">' . $code . '</a>';
1093 }
1094 break;
1095 case 'show':
1096 // "Show" link (only pages and tt_content elements)
1097 if ($table === 'pages' || $table === 'tt_content') {
1098 $code = '<a href="#" onclick="' . htmlspecialchars(
1099 BackendUtility::viewOnClick(($table === 'tt_content' ? $this->id . '#' . $row['uid'] : $row['uid']))
1100 ) . '" title="' . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">' . $code . '</a>';
1101 }
1102 break;
1103 case 'info':
1104 // "Info": (All records)
1105 $code = '<a href="#" onclick="' . htmlspecialchars(('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;')) . '" title="' . htmlspecialchars($lang->getLL('showInfo')) . '">' . $code . '</a>';
1106 break;
1107 default:
1108 // Output the label now:
1109 if ($table === 'pages') {
1110 $code = '<a href="' . htmlspecialchars($this->listURL($uid, '', 'firstElementNumber')) . '" onclick="setHighlight(' . $uid . ')">' . $code . '</a>';
1111 } else {
1112 $code = $this->linkUrlMail($code, $origCode);
1113 }
1114 }
1115 return $code;
1116 }
1117
1118 /**
1119 * Wrapping input code in link to URL or email if $testString is either.
1120 *
1121 * @param string $code code to wrap
1122 * @param string $testString String which is tested for being a URL or email and which will be used for the link if so.
1123 * @return string Link-Wrapped $code value, if $testString was URL or email.
1124 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1125 */
1126 public function linkUrlMail($code, $testString)
1127 {
1128 // Check for URL:
1129 $scheme = parse_url($testString, PHP_URL_SCHEME);
1130 if ($scheme === 'http' || $scheme === 'https' || $scheme === 'ftp') {
1131 return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
1132 }
1133 // Check for email:
1134 if (GeneralUtility::validEmail($testString)) {
1135 return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
1136 }
1137 // Return if nothing else...
1138 return $code;
1139 }
1140
1141 /**
1142 * Creates the URL to this script, including all relevant GPvars
1143 * Fixed GPvars are id, table, imagemode, returnUrl, search_field, search_levels and showLimit
1144 * The GPvars "sortField" and "sortRev" are also included UNLESS they are found in the $exclList variable.
1145 *
1146 * @param string $altId Alternative id value. Enter blank string for the current id ($this->id)
1147 * @param string $table Table name to display. Enter "-1" for the current table.
1148 * @param string $exclList Comma separated list of fields NOT to include ("sortField", "sortRev" or "firstElementNumber")
1149 * @return string URL
1150 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1151 */
1152 public function listURL($altId = '', $table = '-1', $exclList = '')
1153 {
1154 $urlParameters = [];
1155 if ((string)$altId !== '') {
1156 $urlParameters['id'] = $altId;
1157 } else {
1158 $urlParameters['id'] = $this->id;
1159 }
1160 if ($table === '-1') {
1161 $urlParameters['table'] = $this->table;
1162 } else {
1163 $urlParameters['table'] = $table;
1164 }
1165 if ($this->thumbs) {
1166 $urlParameters['imagemode'] = $this->thumbs;
1167 }
1168 if ($this->returnUrl) {
1169 $urlParameters['returnUrl'] = $this->returnUrl;
1170 }
1171 if ((!$exclList || !GeneralUtility::inList($exclList, 'search_field')) && $this->searchString) {
1172 $urlParameters['search_field'] = $this->searchString;
1173 }
1174 if ($this->searchLevels) {
1175 $urlParameters['search_levels'] = $this->searchLevels;
1176 }
1177 if ($this->showLimit) {
1178 $urlParameters['showLimit'] = $this->showLimit;
1179 }
1180 if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
1181 $urlParameters['pointer'] = $this->firstElementNumber;
1182 }
1183 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
1184 $urlParameters['sortField'] = $this->sortField;
1185 }
1186 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
1187 $urlParameters['sortRev'] = $this->sortRev;
1188 }
1189
1190 $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters);
1191
1192 if ($routePath = GeneralUtility::_GP('route')) {
1193 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
1194 $url = (string)$uriBuilder->buildUriFromRoutePath($routePath, $urlParameters);
1195 } else {
1196 $url = GeneralUtility::getIndpEnv('SCRIPT_NAME') . '?' . ltrim(GeneralUtility::implodeArrayForUrl('', $urlParameters), '&');
1197 }
1198 return $url;
1199 }
1200
1201 /**
1202 * Returns "requestUri" - which is basically listURL
1203 * @return string Content of ->listURL()
1204 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1205 */
1206 public function requestUri()
1207 {
1208 return $this->listURL();
1209 }
1210
1211 /**
1212 * Makes the list of fields to select for a table
1213 *
1214 * @param string $table Table name
1215 * @param bool $dontCheckUser If set, users access to the field (non-exclude-fields) is NOT checked.
1216 * @param bool $addDateFields If set, also adds crdate and tstamp fields (note: they will also be added if user is admin or dontCheckUser is set)
1217 * @return string[] Array, where values are fieldnames to include in query
1218 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1219 */
1220 public function makeFieldList($table, $dontCheckUser = false, $addDateFields = false)
1221 {
1222 $backendUser = $this->getBackendUserAuthentication();
1223 // Init fieldlist array:
1224 $fieldListArr = [];
1225 // Check table:
1226 if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
1227 if (isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
1228 // Traverse configured columns and add them to field array, if available for user.
1229 foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fieldValue) {
1230 if ($dontCheckUser || (!$fieldValue['exclude'] || $backendUser->check('non_exclude_fields', $table . ':' . $fN)) && $fieldValue['config']['type'] !== 'passthrough') {
1231 $fieldListArr[] = $fN;
1232 }
1233 }
1234
1235 $fieldListArr[] = 'uid';
1236 $fieldListArr[] = 'pid';
1237
1238 // Add date fields
1239 if ($dontCheckUser || $backendUser->isAdmin() || $addDateFields) {
1240 if ($GLOBALS['TCA'][$table]['ctrl']['tstamp']) {
1241 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['tstamp'];
1242 }
1243 if ($GLOBALS['TCA'][$table]['ctrl']['crdate']) {
1244 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['crdate'];
1245 }
1246 }
1247 // Add more special fields:
1248 if ($dontCheckUser || $backendUser->isAdmin()) {
1249 if ($GLOBALS['TCA'][$table]['ctrl']['cruser_id']) {
1250 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['cruser_id'];
1251 }
1252 if ($GLOBALS['TCA'][$table]['ctrl']['sortby']) {
1253 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
1254 }
1255 if (ExtensionManagementUtility::isLoaded('version') && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
1256 $fieldListArr[] = 't3ver_id';
1257 $fieldListArr[] = 't3ver_state';
1258 $fieldListArr[] = 't3ver_wsid';
1259 }
1260 }
1261 } else {
1262 GeneralUtility::makeInstance(LogManager::class)
1263 ->getLogger(__CLASS__)
1264 ->error('TCA is broken for the table "' . $table . '": no required "columns" entry in TCA.');
1265 }
1266 }
1267 return $fieldListArr;
1268 }
1269
1270 /**
1271 * Get all allowed mount pages to be searched in.
1272 *
1273 * @param int $id Page id
1274 * @param int $depth Depth to go down
1275 * @param string $perms_clause select clause
1276 * @return int[]
1277 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1278 */
1279 protected function getSearchableWebmounts($id, $depth, $perms_clause)
1280 {
1281 $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
1282 $cacheIdentifier = md5('pidList_' . $id . '_' . $depth . '_' . $perms_clause);
1283 $idList = $runtimeCache->get($cacheIdentifier);
1284 if ($idList) {
1285 return $idList;
1286 }
1287
1288 $backendUser = $this->getBackendUserAuthentication();
1289 /** @var PageTreeView $tree */
1290 $tree = GeneralUtility::makeInstance(PageTreeView::class);
1291 $tree->init('AND ' . $perms_clause);
1292 $tree->makeHTML = 0;
1293 $tree->fieldArray = ['uid', 'php_tree_stop'];
1294 $idList = [];
1295
1296 $allowedMounts = !$backendUser->isAdmin() && $id === 0
1297 ? $backendUser->returnWebmounts()
1298 : [$id];
1299
1300 foreach ($allowedMounts as $allowedMount) {
1301 $idList[] = $allowedMount;
1302 if ($depth) {
1303 $tree->getTree($allowedMount, $depth, '');
1304 }
1305 $idList = array_merge($idList, $tree->ids);
1306 }
1307 $runtimeCache->set($cacheIdentifier, $idList);
1308 return $idList;
1309 }
1310
1311 /**
1312 * Redirects to FormEngine if a record is just localized.
1313 *
1314 * @param string $justLocalized String with table, orig uid and language separated by ":
1315 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1316 */
1317 public function localizationRedirect($justLocalized)
1318 {
1319 list($table, $orig_uid, $language) = explode(':', $justLocalized);
1320 if ($GLOBALS['TCA'][$table]
1321 && $GLOBALS['TCA'][$table]['ctrl']['languageField']
1322 && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
1323 ) {
1324 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1325 $queryBuilder->getRestrictions()
1326 ->removeAll()
1327 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
1328 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
1329
1330 $localizedRecordUid = $queryBuilder->select('uid')
1331 ->from($table)
1332 ->where(
1333 $queryBuilder->expr()->eq(
1334 $GLOBALS['TCA'][$table]['ctrl']['languageField'],
1335 $queryBuilder->createNamedParameter($language, \PDO::PARAM_INT)
1336 ),
1337 $queryBuilder->expr()->eq(
1338 $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'],
1339 $queryBuilder->createNamedParameter($orig_uid, \PDO::PARAM_INT)
1340 )
1341 )
1342 ->setMaxResults(1)
1343 ->execute()
1344 ->fetchColumn();
1345
1346 if ($localizedRecordUid !== false) {
1347 // Create parameters and finally run the classic page module for creating a new page translation
1348 $url = $this->listURL();
1349 $editUserAccountUrl = BackendUtility::getModuleUrl(
1350 'record_edit',
1351 [
1352 'edit[' . $table . '][' . $localizedRecordUid . ']' => 'edit',
1353 'returnUrl' => $url
1354 ]
1355 );
1356 HttpUtility::redirect($editUserAccountUrl);
1357 }
1358 }
1359 }
1360
1361 /**
1362 * Set URL parameters to override or add in the listUrl() method.
1363 *
1364 * @param string[] $urlParameters
1365 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1366 */
1367 public function setOverrideUrlParameters(array $urlParameters)
1368 {
1369 $this->overrideUrlParameters = $urlParameters;
1370 }
1371
1372 /**
1373 * Set table display order information
1374 *
1375 * Structure of $orderInformation:
1376 * 'tableName' => [
1377 * 'before' => // comma-separated string list or array of table names
1378 * 'after' => // comma-separated string list or array of table names
1379 * ]
1380 *
1381 * @param array $orderInformation
1382 * @throws \UnexpectedValueException
1383 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1384 */
1385 public function setTableDisplayOrder(array $orderInformation)
1386 {
1387 foreach ($orderInformation as $tableName => &$configuration) {
1388 if (isset($configuration['before'])) {
1389 if (is_string($configuration['before'])) {
1390 $configuration['before'] = GeneralUtility::trimExplode(',', $configuration['before'], true);
1391 } elseif (!is_array($configuration['before'])) {
1392 throw new \UnexpectedValueException('The specified "before" order configuration for table "' . $tableName . '" is invalid.', 1436195933);
1393 }
1394 }
1395 if (isset($configuration['after'])) {
1396 if (is_string($configuration['after'])) {
1397 $configuration['after'] = GeneralUtility::trimExplode(',', $configuration['after'], true);
1398 } elseif (!is_array($configuration['after'])) {
1399 throw new \UnexpectedValueException('The specified "after" order configuration for table "' . $tableName . '" is invalid.', 1436195934);
1400 }
1401 }
1402 }
1403 $this->tableDisplayOrder = $orderInformation;
1404 }
1405
1406 /**
1407 * @return array
1408 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1409 */
1410 public function getOverridePageIdList(): array
1411 {
1412 return $this->overridePageIdList;
1413 }
1414
1415 /**
1416 * @param int[]|array $overridePageIdList
1417 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1418 */
1419 public function setOverridePageIdList(array $overridePageIdList)
1420 {
1421 $this->overridePageIdList = array_map('intval', $overridePageIdList);
1422 }
1423
1424 /**
1425 * Add conditions to the QueryBuilder object ($queryBuilder) to limit a
1426 * query to a list of page IDs based on the current search level setting.
1427 *
1428 * @param string $tableName
1429 * @param QueryBuilder $queryBuilder
1430 * @return QueryBuilder Modified QueryBuilder object
1431 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1432 */
1433 protected function addPageIdConstraint(string $tableName, QueryBuilder $queryBuilder): QueryBuilder
1434 {
1435 // Set search levels:
1436 $searchLevels = $this->searchLevels;
1437
1438 // Set search levels to 999 instead of -1 as the following methods
1439 // do not support -1 as valid value for infinite search.
1440 if ($searchLevels === -1) {
1441 $searchLevels = 999;
1442 }
1443
1444 if ($searchLevels === 0) {
1445 $queryBuilder->andWhere(
1446 $queryBuilder->expr()->eq(
1447 $tableName . '.pid',
1448 $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
1449 )
1450 );
1451 } elseif ($searchLevels > 0) {
1452 $allowedPidList = $this->getSearchableWebmounts($this->id, $searchLevels, $this->perms_clause);
1453 $queryBuilder->andWhere(
1454 $queryBuilder->expr()->in(
1455 $tableName . '.pid',
1456 $queryBuilder->createNamedParameter($allowedPidList, Connection::PARAM_INT_ARRAY)
1457 )
1458 );
1459 }
1460
1461 if (!empty($this->getOverridePageIdList())) {
1462 $queryBuilder->andWhere(
1463 $queryBuilder->expr()->in(
1464 $tableName . '.pid',
1465 $queryBuilder->createNamedParameter($this->getOverridePageIdList(), Connection::PARAM_INT_ARRAY)
1466 )
1467 );
1468 }
1469
1470 return $queryBuilder;
1471 }
1472
1473 /**
1474 * Method used to log deprecated usage of old buildQueryParametersPostProcess hook arguments
1475 *
1476 * @param string $index
1477 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1478 */
1479 protected function logDeprecation(string $index)
1480 {
1481 GeneralUtility::deprecationLog('[index: ' . $index . '] $parameters in "buildQueryParameters"-Hook has been deprecated in v9 and will be remove in v10, use $queryBuilder instead');
1482 }
1483
1484 /**
1485 * @return BackendUserAuthentication
1486 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
1487 */
1488 protected function getBackendUserAuthentication()
1489 {
1490 return $GLOBALS['BE_USER'];
1491 }
1492 }