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