1<?php 2namespace 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 17use TYPO3\CMS\Backend\RecordList\AbstractRecordList; 18use TYPO3\CMS\Backend\Routing\UriBuilder; 19use TYPO3\CMS\Backend\Tree\View\PageTreeView; 20use TYPO3\CMS\Backend\Utility\BackendUtility; 21use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; 22use TYPO3\CMS\Core\Cache\CacheManager; 23use TYPO3\CMS\Core\Database\Connection; 24use TYPO3\CMS\Core\Database\ConnectionPool; 25use TYPO3\CMS\Core\Database\Query\QueryBuilder; 26use TYPO3\CMS\Core\Database\Query\QueryHelper; 27use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction; 28use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; 29use TYPO3\CMS\Core\Imaging\Icon; 30use TYPO3\CMS\Core\Imaging\IconFactory; 31use TYPO3\CMS\Core\Log\LogManager; 32use TYPO3\CMS\Core\Service\DependencyOrderingService; 33use TYPO3\CMS\Core\Type\Bitmask\Permission; 34use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; 35use TYPO3\CMS\Core\Utility\GeneralUtility; 36use TYPO3\CMS\Core\Utility\HttpUtility; 37use 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.0 44 */ 45class 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.0 52 */ 53 public $tableList = ''; 54 55 /** 56 * Return URL 57 * 58 * @var string 59 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 140 */ 141 public $duplicateField; 142 143 /** 144 * Page id 145 * 146 * @var int 147 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 276 */ 277 public $JScode = ''; 278 279 /** 280 * HTML output 281 * 282 * @var string 283 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 340 */ 341 public $duplicateStack = []; 342 343 /** 344 * @var array[] Module configuration 345 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 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.0 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.0 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.0 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.0 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 $pidList = GeneralUtility::intExplode(',', $backendUser->getTSConfig()['options.']['hideRecords.']['pages'] ?? '', true); 439 if (!empty($pidList)) { 440 $permsClause->add($expressionBuilder->notIn('pages.uid', $pidList)); 441 } 442 $this->perms_clause = (string)$permsClause; 443 444 // Get configuration of collapsed tables from user uc and merge with sanitized GP vars 445 $this->tablesCollapsed = is_array($backendUser->uc['moduleData']['list']) 446 ? $backendUser->uc['moduleData']['list'] 447 : []; 448 $collapseOverride = GeneralUtility::_GP('collapse'); 449 if (is_array($collapseOverride)) { 450 foreach ($collapseOverride as $collapseTable => $collapseValue) { 451 if (is_array($GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) { 452 $this->tablesCollapsed[$collapseTable] = $collapseValue; 453 } 454 } 455 // Save modified user uc 456 $backendUser->uc['moduleData']['list'] = $this->tablesCollapsed; 457 $backendUser->writeUC($backendUser->uc); 458 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl')); 459 if ($returnUrl !== '') { 460 HttpUtility::redirect($returnUrl); 461 } 462 } 463 $this->initializeLanguages(); 464 } 465 466 /** 467 * Traverses the table(s) to be listed and renders the output code for each: 468 * The HTML is accumulated in $this->HTMLcode 469 * Finishes off with a stopper-gif 470 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 471 */ 472 public function generateList() 473 { 474 // Set page record in header 475 $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id); 476 $hideTablesArray = GeneralUtility::trimExplode(',', $this->hideTables); 477 478 $backendUser = $this->getBackendUserAuthentication(); 479 480 // pre-process tables and add sorting instructions 481 $tableNames = array_flip(array_keys($GLOBALS['TCA'])); 482 foreach ($tableNames as $tableName => &$config) { 483 $hideTable = false; 484 485 // Checking if the table should be rendered: 486 // Checks that we see only permitted/requested tables: 487 if ($this->table && $tableName !== $this->table 488 || $this->tableList && !GeneralUtility::inList($this->tableList, $tableName) 489 || !$backendUser->check('tables_select', $tableName) 490 ) { 491 $hideTable = true; 492 } 493 494 if (!$hideTable) { 495 // Don't show table if hidden by TCA ctrl section 496 // Don't show table if hidden by pageTSconfig mod.web_list.hideTables 497 $hideTable = $hideTable 498 || !empty($GLOBALS['TCA'][$tableName]['ctrl']['hideTable']) 499 || in_array($tableName, $hideTablesArray, true) 500 || in_array('*', $hideTablesArray, true); 501 // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table 502 if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) { 503 $hideTable = (bool)$this->tableTSconfigOverTCA[$tableName . '.']['hideTable']; 504 } 505 } 506 if ($hideTable) { 507 unset($tableNames[$tableName]); 508 } else { 509 if (isset($this->tableDisplayOrder[$tableName])) { 510 // Copy display order information 511 $tableNames[$tableName] = $this->tableDisplayOrder[$tableName]; 512 } else { 513 $tableNames[$tableName] = []; 514 } 515 } 516 } 517 unset($config); 518 519 $orderedTableNames = GeneralUtility::makeInstance(DependencyOrderingService::class) 520 ->orderByDependencies($tableNames); 521 522 foreach ($orderedTableNames as $tableName => $_) { 523 // check if we are in single- or multi-table mode 524 if ($this->table) { 525 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']) 526 ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'] 527 : $this->itemsLimitSingleTable; 528 } else { 529 // if there are no records in table continue current foreach 530 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) 531 ->getQueryBuilderForTable($tableName); 532 $queryBuilder->getRestrictions() 533 ->removeAll() 534 ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) 535 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); 536 $queryBuilder = $this->addPageIdConstraint($tableName, $queryBuilder); 537 $firstRow = $queryBuilder->select('uid') 538 ->from($tableName) 539 ->execute() 540 ->fetch(); 541 if (!is_array($firstRow)) { 542 continue; 543 } 544 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']) 545 ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'] 546 : $this->itemsLimitPerTable; 547 } 548 if ($this->showLimit) { 549 $this->iLimit = $this->showLimit; 550 } 551 // Setting fields to select: 552 if ($this->allFields) { 553 $fields = $this->makeFieldList($tableName); 554 $fields[] = 'tstamp'; 555 $fields[] = 'crdate'; 556 $fields[] = '_PATH_'; 557 $fields[] = '_CONTROL_'; 558 if (is_array($this->setFields[$tableName])) { 559 $fields = array_intersect($fields, $this->setFields[$tableName]); 560 } else { 561 $fields = []; 562 } 563 } else { 564 $fields = []; 565 } 566 567 // Finally, render the list: 568 $this->HTMLcode .= $this->getTable($tableName, $this->id, implode(',', $fields)); 569 } 570 } 571 572 /** 573 * To be implemented in extending classes. 574 * 575 * @param string $tableName 576 * @param int $id 577 * @param string $fields List of fields to show in the listing. Pseudo fields will be added including the record header. 578 * @return string HTML code 579 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 580 */ 581 public function getTable($tableName, $id, $fields = '') 582 { 583 return ''; 584 } 585 586 /** 587 * Creates the search box 588 * 589 * @param bool $formFields If TRUE, the search box is wrapped in its own form-tags 590 * @return string HTML for the search box 591 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 592 */ 593 public function getSearchBox($formFields = true) 594 { 595 /** @var IconFactory $iconFactory */ 596 $iconFactory = GeneralUtility::makeInstance(IconFactory::class); 597 $lang = $this->getLanguageService(); 598 // Setting form-elements, if applicable: 599 $formElements = ['', '']; 600 if ($formFields) { 601 $formElements = ['<form action="' . htmlspecialchars($this->listURL('', '-1', 'firstElementNumber,search_field')) . '" method="post">', '</form>']; 602 } 603 // Make level selector: 604 $opt = []; 605 606 // "New" generation of search levels ... based on TS config 607 $config = BackendUtility::getPagesTSconfig($this->id); 608 $searchLevelsFromTSconfig = $config['mod.']['web_list.']['searchLevel.']['items.']; 609 $searchLevelItems = []; 610 611 // get translated labels for search levels from pagets 612 foreach ($searchLevelsFromTSconfig as $keySearchLevel => $labelConfigured) { 613 $label = $lang->sL('LLL:' . $labelConfigured); 614 if ($label === '') { 615 $label = $labelConfigured; 616 } 617 $searchLevelItems[$keySearchLevel] = $label; 618 } 619 620 foreach ($searchLevelItems as $kv => $label) { 621 $opt[] = '<option value="' . $kv . '"' . ($kv === $this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>'; 622 } 623 $lMenu = '<select class="form-control" name="search_levels" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search_levels')) . '" id="search_levels">' . implode('', $opt) . '</select>'; 624 // Table with the search box: 625 $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') . ';"> 626 ' . $formElements[0] . ' 627 <div id="typo3-dblist-search"> 628 <div class="panel panel-default"> 629 <div class="panel-body"> 630 <div class="row"> 631 <div class="form-group col-xs-12"> 632 <label for="search_field">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.searchString')) . ': </label> 633 <input class="form-control" type="search" placeholder="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchString')) . '" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.searchString')) . '" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '" /> 634 </div> 635 <div class="form-group col-xs-12 col-sm-6"> 636 <label for="search_levels">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.search_levels')) . ': </label> 637 ' . $lMenu . ' 638 </div> 639 <div class="form-group col-xs-12 col-sm-6"> 640 <label for="showLimit">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.label.limit')) . ': </label> 641 <input class="form-control" type="number" min="0" max="10000" placeholder="10" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.limit')) . '" name="showLimit" id="showLimit" value="' . htmlspecialchars(($this->showLimit ? $this->showLimit : '')) . '" /> 642 </div> 643 <div class="form-group col-xs-12"> 644 <div class="form-control-wrap"> 645 <button type="submit" class="btn btn-default" name="search" title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.title.search')) . '"> 646 ' . $iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . ' ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.search')) . ' 647 </button> 648 </div> 649 </div> 650 </div> 651 </div> 652 </div> 653 </div> 654 ' . $formElements[1] . '</div>'; 655 return $content; 656 } 657 658 /****************************** 659 * 660 * Various helper functions 661 * 662 ******************************/ 663 /** 664 * Setting the field names to display in extended list. 665 * Sets the internal variable $this->setFields 666 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 667 */ 668 public function setDispFields() 669 { 670 $backendUser = $this->getBackendUserAuthentication(); 671 // Getting from session: 672 $dispFields = $backendUser->getModuleData('list/displayFields'); 673 // If fields has been inputted, then set those as the value and push it to session variable: 674 if (is_array($this->displayFields)) { 675 reset($this->displayFields); 676 $tKey = key($this->displayFields); 677 $dispFields[$tKey] = $this->displayFields[$tKey]; 678 $backendUser->pushModuleData('list/displayFields', $dispFields); 679 } 680 // Setting result: 681 $this->setFields = $dispFields; 682 } 683 684 /** 685 * Create thumbnail code for record/field 686 * 687 * @param mixed[] $row Record array 688 * @param string $table Table (record is from) 689 * @param string $field Field name for which thumbnail are to be rendered. 690 * @return string HTML for thumbnails, if any. 691 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 692 */ 693 public function thumbCode($row, $table, $field) 694 { 695 return BackendUtility::thumbCode($row, $table, $field); 696 } 697 698 /** 699 * Returns a QueryBuilder configured to select $fields from $table where the pid is restricted 700 * depending on the current searchlevel setting. 701 * 702 * @param string $table Table name 703 * @param int $pageId Page id Only used to build the search constraints, getPageIdConstraint() used for restrictions 704 * @param string[] $additionalConstraints Additional part for where clause 705 * @param string[] $fields Field list to select, * for all 706 * @return \TYPO3\CMS\Core\Database\Query\QueryBuilder 707 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 708 */ 709 public function getQueryBuilder( 710 string $table, 711 int $pageId, 712 array $additionalConstraints = [], 713 array $fields = ['*'] 714 ): QueryBuilder { 715 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) 716 ->getQueryBuilderForTable($table); 717 $queryBuilder->getRestrictions() 718 ->removeAll() 719 ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) 720 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); 721 $queryBuilder 722 ->select(...$fields) 723 ->from($table); 724 725 if (!empty($additionalConstraints)) { 726 $queryBuilder->andWhere(...$additionalConstraints); 727 } 728 729 $queryBuilder = $this->prepareQueryBuilder($table, $pageId, $fields, $additionalConstraints, $queryBuilder); 730 731 return $queryBuilder; 732 } 733 734 /** 735 * Return the modified QueryBuilder object ($queryBuilder) which will be 736 * used to select the records from a table $table with pid = $this->pidList 737 * 738 * @param string $table Table name 739 * @param int $pageId Page id Only used to build the search constraints, $this->pidList is used for restrictions 740 * @param string[] $fieldList List of fields to select from the table 741 * @param string[] $additionalConstraints Additional part for where clause 742 * @param QueryBuilder $queryBuilder 743 * @param bool $addSorting 744 * @return QueryBuilder 745 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 746 */ 747 protected function prepareQueryBuilder( 748 string $table, 749 int $pageId, 750 array $fieldList = ['*'], 751 array $additionalConstraints = [], 752 QueryBuilder $queryBuilder, 753 bool $addSorting = true 754 ): QueryBuilder { 755 $parameters = [ 756 'table' => $table, 757 'fields' => $fieldList, 758 'groupBy' => null, 759 'orderBy' => null, 760 'firstResult' => $this->firstElementNumber ?: null, 761 'maxResults' => $this->iLimit ?: null 762 ]; 763 764 if ($this->iLimit > 0) { 765 $queryBuilder->setMaxResults($this->iLimit); 766 } 767 768 if ($addSorting) { 769 if ($this->sortField && in_array($this->sortField, $this->makeFieldList($table, 1))) { 770 $queryBuilder->orderBy($this->sortField, $this->sortRev ? 'DESC' : 'ASC'); 771 } else { 772 $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ?: $GLOBALS['TCA'][$table]['ctrl']['default_sortby']; 773 $orderBys = QueryHelper::parseOrderBy((string)$orderBy); 774 foreach ($orderBys as $orderBy) { 775 $queryBuilder->addOrderBy($orderBy[0], $orderBy[1]); 776 } 777 } 778 } 779 780 // Build the query constraints 781 $queryBuilder = $this->addPageIdConstraint($table, $queryBuilder); 782 $searchWhere = $this->makeSearchString($table, $pageId); 783 if (!empty($searchWhere)) { 784 $queryBuilder->andWhere($searchWhere); 785 } 786 787 // Filtering on displayable pages (permissions): 788 if ($table === 'pages' && $this->perms_clause) { 789 $queryBuilder->andWhere($this->perms_clause); 790 } 791 792 // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set 793 if (!empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) 794 && (GeneralUtility::inList($this->hideTranslations, $table) || $this->hideTranslations === '*') 795 ) { 796 $queryBuilder->andWhere($queryBuilder->expr()->eq( 797 $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], 798 0 799 )); 800 } 801 802 $hookName = DatabaseRecordList::class; 803 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookName]['buildQueryParameters'])) { 804 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, the modifyQuery hook should be used instead. 805 trigger_error('The hook ($GLOBALS[\'TYPO3_CONF_VARS\'][\'SC_OPTIONS\'][' . $hookName . '][\'buildQueryParameters\']) will be removed in TYPO3 v10.0, the modifyQuery hook should be used instead.', E_USER_DEPRECATED); 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.0 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.0 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.0 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.0 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.0 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.0 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:core/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:core/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.TYPO3.InfoWindow.showItem(\'' . $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.0 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.0 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') . HttpUtility::buildQueryString($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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 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.0 1461 */ 1462 protected function logDeprecation(string $index) 1463 { 1464 trigger_error('[index: ' . $index . '] $parameters in "buildQueryParameters"-Hook will be removed in TYPO3 v10.0, use $queryBuilder instead.', E_USER_DEPRECATED); 1465 } 1466 1467 /** 1468 * @return BackendUserAuthentication 1469 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 1470 */ 1471 protected function getBackendUserAuthentication() 1472 { 1473 return $GLOBALS['BE_USER']; 1474 } 1475} 1476