[TASK] Re-work/simplify copyright header in PHP files - Part 2
[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\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Child class for rendering of Web > List (not the final class.
22 * Shared between Web>List (db_list.php) and Web>Page (sysext/cms/layout/db_layout.php)
23 *
24 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
25 * @see localRecordList
26 */
27 class AbstractDatabaseRecordList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
28
29 // External, static:
30 // Specify a list of tables which are the only ones allowed to be displayed.
31 /**
32 * @todo Define visibility
33 */
34 public $tableList = '';
35
36 // Return URL
37 /**
38 * @todo Define visibility
39 */
40 public $returnUrl = '';
41
42 // Boolean. Thumbnails on records containing files (pictures)
43 /**
44 * @todo Define visibility
45 */
46 public $thumbs = 0;
47
48 // default Max items shown per table in "multi-table mode", may be overridden by tables.php
49 /**
50 * @todo Define visibility
51 */
52 public $itemsLimitPerTable = 20;
53
54 // default Max items shown per table in "single-table mode", may be overridden by tables.php
55 /**
56 * @todo Define visibility
57 */
58 public $itemsLimitSingleTable = 100;
59
60 /**
61 * @todo Define visibility
62 */
63 public $widthGif = '<img src="clear.gif" width="1" height="4" hspace="160" alt="" />';
64
65 // Current script name
66 /**
67 * @todo Define visibility
68 */
69 public $script = 'index.php';
70
71 // Indicates if all available fields for a user should be selected or not.
72 /**
73 * @todo Define visibility
74 */
75 public $allFields = 0;
76
77 // Whether to show localization view or not.
78 /**
79 * @todo Define visibility
80 */
81 public $localizationView = FALSE;
82
83 // Internal, static: GPvar:
84 // If set, csvList is outputted.
85 /**
86 * @todo Define visibility
87 */
88 public $csvOutput = FALSE;
89
90 // Field, to sort list by
91 /**
92 * @todo Define visibility
93 */
94 public $sortField;
95
96 // Field, indicating to sort in reverse order.
97 /**
98 * @todo Define visibility
99 */
100 public $sortRev;
101
102 // Array, containing which fields to display in extended mode
103 /**
104 * @todo Define visibility
105 */
106 public $displayFields;
107
108 // String, can contain the field name from a table which must have duplicate values marked.
109 /**
110 * @todo Define visibility
111 */
112 public $duplicateField;
113
114 // Internal, static:
115 // Page id
116 /**
117 * @todo Define visibility
118 */
119 public $id;
120
121 // Tablename if single-table mode
122 /**
123 * @todo Define visibility
124 */
125 public $table = '';
126
127 // If TRUE, records are listed only if a specific table is selected.
128 /**
129 * @todo Define visibility
130 */
131 public $listOnlyInSingleTableMode = FALSE;
132
133 // Pointer for browsing list
134 /**
135 * @todo Define visibility
136 */
137 public $firstElementNumber = 0;
138
139 // Search string
140 /**
141 * @todo Define visibility
142 */
143 public $searchString = '';
144
145 // Levels to search down.
146 /**
147 * @todo Define visibility
148 */
149 public $searchLevels = '';
150
151 // Number of records to show
152 /**
153 * @todo Define visibility
154 */
155 public $showLimit = 0;
156
157 // Query part for either a list of ids "pid IN (1,2,3)" or a single id "pid = 123" from
158 // which to select/search etc. (when search-levels are set high). See start()
159 /**
160 * @todo Define visibility
161 */
162 public $pidSelect = '';
163
164 // Page select permissions
165 /**
166 * @todo Define visibility
167 */
168 public $perms_clause = '';
169
170 // Some permissions...
171 /**
172 * @todo Define visibility
173 */
174 public $calcPerms = 0;
175
176 // Mode for what happens when a user clicks the title of a record.
177 /**
178 * @todo Define visibility
179 */
180 public $clickTitleMode = '';
181
182 // Shared module configuration, used by localization features
183 /**
184 * @todo Define visibility
185 */
186 public $modSharedTSconfig = array();
187
188 // Loaded with page record with version overlay if any.
189 /**
190 * @todo Define visibility
191 */
192 public $pageRecord = array();
193
194 // Tables which should not get listed
195 /**
196 * @todo Define visibility
197 */
198 public $hideTables = '';
199
200 /**
201 * Tables which should not list their translations
202 *
203 * @var $hideTranslations string
204 */
205 public $hideTranslations = '';
206
207 //TSconfig which overwrites TCA-Settings
208 /**
209 * @todo Define visibility
210 */
211 public $tableTSconfigOverTCA = array();
212
213 // Array of collapsed / uncollapsed tables in multi table view
214 /**
215 * @todo Define visibility
216 */
217 public $tablesCollapsed = array();
218
219 // Internal, dynamic:
220 // JavaScript code accumulation
221 /**
222 * @todo Define visibility
223 */
224 public $JScode = '';
225
226 // HTML output
227 /**
228 * @todo Define visibility
229 */
230 public $HTMLcode = '';
231
232 // "LIMIT " in SQL...
233 /**
234 * @todo Define visibility
235 */
236 public $iLimit = 0;
237
238 // Counting the elements no matter what...
239 /**
240 * @todo Define visibility
241 */
242 public $eCounter = 0;
243
244 // Set to the total number of items for a table when selecting.
245 /**
246 * @todo Define visibility
247 */
248 public $totalItems = '';
249
250 // Cache for record path
251 /**
252 * @todo Define visibility
253 */
254 public $recPath_cache = array();
255
256 // Fields to display for the current table
257 /**
258 * @todo Define visibility
259 */
260 public $setFields = array();
261
262 // Used for tracking next/prev uids
263 /**
264 * @todo Define visibility
265 */
266 public $currentTable = array();
267
268 // Used for tracking duplicate values of fields
269 /**
270 * @todo Define visibility
271 */
272 public $duplicateStack = array();
273
274 // module configuratio
275 /**
276 * @todo Define visibility
277 */
278 public $modTSconfig;
279
280 /**
281 * Override/add urlparameters in listUrl() method
282 * @var array
283 */
284 protected $overrideUrlParameters = array();
285
286 /**
287 * Initializes the list generation
288 *
289 * @param integer $id Page id for which the list is rendered. Must be >= 0
290 * @param string $table Tablename - if extended mode where only one table is listed at a time.
291 * @param integer $pointer Browsing pointer.
292 * @param string $search Search word, if any
293 * @param integer $levels Number of levels to search down the page tree
294 * @param integer $showLimit Limit of records to be listed.
295 * @return void
296 * @todo Define visibility
297 */
298 public function start($id, $table, $pointer, $search = '', $levels = '', $showLimit = 0) {
299 // Setting internal variables:
300 // sets the parent id
301 $this->id = (int)$id;
302 if ($GLOBALS['TCA'][$table]) {
303 // Setting single table mode, if table exists:
304 $this->table = $table;
305 }
306 $this->firstElementNumber = $pointer;
307 $this->searchString = trim($search);
308 $this->searchLevels = trim($levels);
309 $this->showLimit = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($showLimit, 0, 10000);
310 // Setting GPvars:
311 $this->csvOutput = GeneralUtility::_GP('csv') ? TRUE : FALSE;
312 $this->sortField = GeneralUtility::_GP('sortField');
313 $this->sortRev = GeneralUtility::_GP('sortRev');
314 $this->displayFields = GeneralUtility::_GP('displayFields');
315 $this->duplicateField = GeneralUtility::_GP('duplicateField');
316 if (GeneralUtility::_GP('justLocalized')) {
317 $this->localizationRedirect(GeneralUtility::_GP('justLocalized'));
318 }
319 // Init dynamic vars:
320 $this->counter = 0;
321 $this->JScode = '';
322 $this->HTMLcode = '';
323 // Limits
324 if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
325 $this->itemsLimitPerTable = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange((int)$this->modTSconfig['properties']['itemsLimitPerTable'], 1, 10000);
326 }
327 if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
328 $this->itemsLimitSingleTable = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange((int)$this->modTSconfig['properties']['itemsLimitSingleTable'], 1, 10000);
329 }
330 // Set search levels:
331 $searchLevels = (int)$this->searchLevels;
332 $this->perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
333 // This will hide records from display - it has nothing todo with user rights!!
334 if ($pidList = $GLOBALS['BE_USER']->getTSConfigVal('options.hideRecords.pages')) {
335 if ($pidList = $GLOBALS['TYPO3_DB']->cleanIntList($pidList)) {
336 $this->perms_clause .= ' AND pages.uid NOT IN (' . $pidList . ')';
337 }
338 }
339 // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
340 $this->tablesCollapsed = is_array($GLOBALS['BE_USER']->uc['moduleData']['list']) ? $GLOBALS['BE_USER']->uc['moduleData']['list'] : array();
341 $collapseOverride = GeneralUtility::_GP('collapse');
342 if (is_array($collapseOverride)) {
343 foreach ($collapseOverride as $collapseTable => $collapseValue) {
344 if (is_array($GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) {
345 $this->tablesCollapsed[$collapseTable] = $collapseValue;
346 }
347 }
348 // Save modified user uc
349 $GLOBALS['BE_USER']->uc['moduleData']['list'] = $this->tablesCollapsed;
350 $GLOBALS['BE_USER']->writeUC($GLOBALS['BE_USER']->uc);
351 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
352 if ($returnUrl !== '') {
353 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($returnUrl);
354 }
355 }
356 if ($searchLevels > 0) {
357 $allowedMounts = $this->getSearchableWebmounts($this->id, $searchLevels, $this->perms_clause);
358 $pidList = implode(',', $GLOBALS['TYPO3_DB']->cleanIntArray($allowedMounts));
359 $this->pidSelect = 'pid IN (' . $pidList . ')';
360 } elseif ($searchLevels < 0) {
361 // Search everywhere
362 $this->pidSelect = '1=1';
363 } else {
364 $this->pidSelect = 'pid=' . (int)$id;
365 }
366 // Initialize languages:
367 if ($this->localizationView) {
368 $this->initializeLanguages();
369 }
370 }
371
372 /**
373 * Traverses the table(s) to be listed and renders the output code for each:
374 * The HTML is accumulated in $this->HTMLcode
375 * Finishes off with a stopper-gif
376 *
377 * @return void
378 * @todo Define visibility
379 */
380 public function generateList() {
381 // Set page record in header
382 $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id);
383 // Traverse the TCA table array:
384 foreach ($GLOBALS['TCA'] as $tableName => $value) {
385 // Checking if the table should be rendered:
386 // Checks that we see only permitted/requested tables:
387 if ((!$this->table || $tableName == $this->table) && (!$this->tableList || GeneralUtility::inList($this->tableList, $tableName)) && $GLOBALS['BE_USER']->check('tables_select', $tableName)) {
388 // Don't show table if hidden by TCA ctrl section
389 $hideTable = $GLOBALS['TCA'][$tableName]['ctrl']['hideTable'] ? TRUE : FALSE;
390 // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
391 if (in_array($tableName, GeneralUtility::trimExplode(',', $this->hideTables))) {
392 $hideTable = TRUE;
393 }
394 // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
395 if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
396 $hideTable = $this->tableTSconfigOverTCA[$tableName . '.']['hideTable'] ? TRUE : FALSE;
397 }
398 if ($hideTable) {
399 continue;
400 }
401 // check if we are in single- or multi-table mode
402 if ($this->table) {
403 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']) ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems'] : $this->itemsLimitSingleTable;
404 } else {
405 // if there are no records in table continue current foreach
406 $firstRow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
407 'uid',
408 $tableName,
409 $this->pidSelect . BackendUtility::deleteClause($tableName) . BackendUtility::versioningPlaceholderClause($tableName)
410 );
411 if ($firstRow === FALSE) {
412 continue;
413 }
414 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']) ? (int)$GLOBALS['TCA'][$tableName]['interface']['maxDBListItems'] : $this->itemsLimitPerTable;
415 }
416 if ($this->showLimit) {
417 $this->iLimit = $this->showLimit;
418 }
419 // Setting fields to select:
420 if ($this->allFields) {
421 $fields = $this->makeFieldList($tableName);
422 $fields[] = 'tstamp';
423 $fields[] = 'crdate';
424 $fields[] = '_PATH_';
425 $fields[] = '_CONTROL_';
426 if (is_array($this->setFields[$tableName])) {
427 $fields = array_intersect($fields, $this->setFields[$tableName]);
428 } else {
429 $fields = array();
430 }
431 } else {
432 $fields = array();
433 }
434 // Find ID to use (might be different for "versioning_followPages" tables)
435 if ((int)$this->searchLevels === 0) {
436 $this->pidSelect = 'pid=' . (int)$this->id;
437 }
438 // Finally, render the list:
439 $this->HTMLcode .= $this->getTable($tableName, $this->id, implode(',', $fields));
440 }
441 }
442 }
443
444 /**
445 * Creates the search box
446 *
447 * @param boolean $formFields If TRUE, the search box is wrapped in its own form-tags
448 * @return string HTML for the search box
449 * @todo Define visibility
450 */
451 public function getSearchBox($formFields = 1) {
452 // Setting form-elements, if applicable:
453 $formElements = array('', '');
454 if ($formFields) {
455 $formElements = array('<form action="' . htmlspecialchars($this->listURL('', -1, 'firstElementNumber')) . '" method="post">', '</form>');
456 }
457 // Make level selector:
458 $opt = array();
459 $parts = explode('|', $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels'));
460 foreach ($parts as $kv => $label) {
461 $opt[] = '<option value="' . $kv . '"' . ($kv == (int)$this->searchLevels ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
462 }
463 $lMenu = '<select name="search_levels">' . implode('', $opt) . '</select>';
464 // Table with the search box:
465 $content = '<div class="db_list-searchbox-form">
466 ' . $formElements[0] . '
467
468 <!--
469 Search box:
470 -->
471 <table border="0" cellpadding="0" cellspacing="0" id="typo3-dblist-search">
472 <tr>
473 <td><label for="search_field">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchString', TRUE) . '</label></td>
474 <td><input type="text" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' /></td>
475 <td>' . $lMenu . '</td>
476 <td><input type="submit" name="search" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.search', TRUE) . '" /></td>
477 </tr>
478 <tr>
479 <td><label for="showLimit">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showRecords', TRUE) . ':</label></td>
480 <td colspan="3"><input type="text" name="showLimit" id="showLimit" value="' . htmlspecialchars(($this->showLimit ? $this->showLimit : '')) . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(4) . ' /></td>
481 </tr>
482 </table>
483 ' . $formElements[1] . '</div>';
484 return $content;
485 }
486
487 /******************************
488 *
489 * Various helper functions
490 *
491 ******************************/
492 /**
493 * Setting the field names to display in extended list.
494 * Sets the internal variable $this->setFields
495 *
496 * @return void
497 * @todo Define visibility
498 */
499 public function setDispFields() {
500 // Getting from session:
501 $dispFields = $GLOBALS['BE_USER']->getModuleData('list/displayFields');
502 // If fields has been inputted, then set those as the value and push it to session variable:
503 if (is_array($this->displayFields)) {
504 reset($this->displayFields);
505 $tKey = key($this->displayFields);
506 $dispFields[$tKey] = $this->displayFields[$tKey];
507 $GLOBALS['BE_USER']->pushModuleData('list/displayFields', $dispFields);
508 }
509 // Setting result:
510 $this->setFields = $dispFields;
511 }
512
513 /**
514 * Create thumbnail code for record/field
515 *
516 * @param array $row Record array
517 * @param string $table Table (record is from)
518 * @param string $field Field name for which thumbnail are to be rendered.
519 * @return string HTML for thumbnails, if any.
520 * @todo Define visibility
521 */
522 public function thumbCode($row, $table, $field) {
523 return BackendUtility::thumbCode($row, $table, $field, $this->backPath);
524 }
525
526 /**
527 * Returns the SQL-query array to select the records from a table $table with pid = $id
528 *
529 * @param string $table Table name
530 * @param integer $id Page id (NOT USED! $this->pidSelect is used instead)
531 * @param string $addWhere Additional part for where clause
532 * @param string $fieldList Field list to select, * for all (for "SELECT [fieldlist] FROM ...")
533 * @return array Returns query array
534 * @todo Define visibility
535 */
536 public function makeQueryArray($table, $id, $addWhere = '', $fieldList = '*') {
537 $hookObjectsArr = array();
538 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'])) {
539 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'] as $classRef) {
540 $hookObjectsArr[] = GeneralUtility::getUserObj($classRef);
541 }
542 }
543 // Set ORDER BY:
544 $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby'] : $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
545 if ($this->sortField) {
546 if (in_array($this->sortField, $this->makeFieldList($table, 1))) {
547 $orderBy = 'ORDER BY ' . $this->sortField;
548 if ($this->sortRev) {
549 $orderBy .= ' DESC';
550 }
551 }
552 }
553 // Set LIMIT:
554 $limit = $this->iLimit ? ($this->firstElementNumber ? $this->firstElementNumber . ',' : '') . ($this->iLimit + 1) : '';
555 // Filtering on displayable pages (permissions):
556 $pC = $table == 'pages' && $this->perms_clause ? ' AND ' . $this->perms_clause : '';
557 // Adding search constraints:
558 $search = $this->makeSearchString($table, $id);
559 // Compiling query array:
560 $queryParts = array(
561 'SELECT' => $fieldList,
562 'FROM' => $table,
563 'WHERE' => $this->pidSelect . ' ' . $pC . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table) . ' ' . $addWhere . ' ' . $search,
564 'GROUPBY' => '',
565 'ORDERBY' => $GLOBALS['TYPO3_DB']->stripOrderBy($orderBy),
566 'LIMIT' => $limit
567 );
568 // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
569 if ((in_array($table, GeneralUtility::trimExplode(',', $this->hideTranslations)) || $this->hideTranslations === '*') && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && $table !== 'pages_language_overlay') {
570 $queryParts['WHERE'] .= ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=0 ';
571 }
572 // Apply hook as requested in http://forge.typo3.org/issues/16634
573 foreach ($hookObjectsArr as $hookObj) {
574 if (method_exists($hookObj, 'makeQueryArray_post')) {
575 $_params = array(
576 'orderBy' => $orderBy,
577 'limit' => $limit,
578 'pC' => $pC,
579 'search' => $search
580 );
581 $hookObj->makeQueryArray_post($queryParts, $this, $table, $id, $addWhere, $fieldList, $_params);
582 }
583 }
584 // Return query:
585 return $queryParts;
586 }
587
588 /**
589 * Based on input query array (query for selecting count(*) from a table) it will select the number of records and set the value in $this->totalItems
590 *
591 * @param array $queryParts Query array
592 * @return void
593 * @see makeQueryArray()
594 * @todo Define visibility
595 */
596 public function setTotalItems($queryParts) {
597 $this->totalItems = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $queryParts['FROM'], $queryParts['WHERE']);
598 }
599
600 /**
601 * Creates part of query for searching after a word ($this->searchString)
602 * fields in input table.
603 *
604 * @param string $table Table, in which the fields are being searched.
605 * @param integer $currentPid Page id for the possible search limit. -1 only if called from an old XCLASS.
606 * @return string Returns part of WHERE-clause for searching, if applicable.
607 * @todo Define visibility
608 */
609 public function makeSearchString($table, $currentPid = -1) {
610 $result = '';
611 $currentPid = (int)$currentPid;
612 $tablePidField = $table == 'pages' ? 'uid' : 'pid';
613 // Make query, only if table is valid and a search string is actually defined:
614 if ($this->searchString) {
615 $result = ' AND 0=1';
616 $searchableFields = $this->getSearchFields($table);
617 if (count($searchableFields) > 0) {
618 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->searchString)) {
619 $whereParts = array(
620 'uid=' . $this->searchString
621 );
622 foreach ($searchableFields as $fieldName) {
623 if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
624 $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
625 $condition = $fieldName . '=' . $this->searchString;
626 if ($fieldConfig['type'] == 'input' && $fieldConfig['eval'] && GeneralUtility::inList($fieldConfig['eval'], 'int')) {
627 if (is_array($fieldConfig['search']) && in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
628 $condition = '(' . $condition . ' AND ' . $tablePidField . '=' . $currentPid . ')';
629 }
630 $whereParts[] = $condition;
631 } elseif (
632 $fieldConfig['type'] == 'text' ||
633 $fieldConfig['type'] == 'flex' ||
634 ($fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval'])))) {
635 $condition = $fieldName . ' LIKE \'%' . $this->searchString . '%\'';
636 $whereParts[] = $condition;
637 }
638 }
639 }
640 } else {
641 $whereParts = array();
642 $like = '\'%' . $GLOBALS['TYPO3_DB']->quoteStr($GLOBALS['TYPO3_DB']->escapeStrForLike($this->searchString, $table), $table) . '%\'';
643 foreach ($searchableFields as $fieldName) {
644 if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
645 $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
646 $format = 'LCASE(%s) LIKE LCASE(%s)';
647 if (is_array($fieldConfig['search'])) {
648 if (in_array('case', $fieldConfig['search'])) {
649 $format = '%s LIKE %s';
650 }
651 if (in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
652 $format = '(' . $format . ' AND ' . $tablePidField . '=' . $currentPid . ')';
653 }
654 if ($fieldConfig['search']['andWhere']) {
655 $format = '((' . $fieldConfig['search']['andWhere'] . ') AND (' . $format . '))';
656 }
657 }
658 if ($fieldConfig['type'] == 'text' || $fieldConfig['type'] == 'flex' || $fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval']))) {
659 $whereParts[] = sprintf($format, $fieldName, $like);
660 }
661 }
662 }
663 }
664 // If search-fields were defined (and there always are) we create the query:
665 if (count($whereParts)) {
666 $result = ' AND (' . implode(' OR ', $whereParts) . ')';
667 }
668 }
669 }
670 return $result;
671 }
672
673 /**
674 * Fetches a list of fields to use in the Backend search for the given table.
675 *
676 * @param string $tableName
677 * @return array
678 */
679 protected function getSearchFields($tableName) {
680 $fieldArray = array();
681 $fieldListWasSet = FALSE;
682 // Get fields from ctrl section of TCA first
683 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
684 $fieldArray = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], TRUE);
685 $fieldListWasSet = TRUE;
686 }
687 // Call hook to add or change the list
688 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
689 $hookParameters = array(
690 'tableHasSearchConfiguration' => $fieldListWasSet,
691 'tableName' => $tableName,
692 'searchFields' => &$fieldArray,
693 'searchString' => $this->searchString
694 );
695 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
696 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
697 }
698 }
699 return $fieldArray;
700 }
701
702 /**
703 * Returns the title (based on $code) of a table ($table) with the proper link around. For headers over tables.
704 * The link will cause the display of all extended mode or not for the table.
705 *
706 * @param string $table Table name
707 * @param string $code Table label
708 * @return string The linked table label
709 * @todo Define visibility
710 */
711 public function linkWrapTable($table, $code) {
712 if ($this->table != $table) {
713 return '<a href="' . htmlspecialchars($this->listURL('', $table, 'firstElementNumber')) . '">' . $code . '</a>';
714 } else {
715 return '<a href="' . htmlspecialchars($this->listURL('', '', 'sortField,sortRev,table,firstElementNumber')) . '">' . $code . '</a>';
716 }
717 }
718
719 /**
720 * 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...)
721 *
722 * @param string $table Table name
723 * @param integer $uid Item uid
724 * @param string $code Item title (not htmlspecialchars()'ed yet)
725 * @param array $row Item row
726 * @return string The item title. Ready for HTML output (is htmlspecialchars()'ed)
727 * @todo Define visibility
728 */
729 public function linkWrapItems($table, $uid, $code, $row) {
730 $origCode = $code;
731 // If the title is blank, make a "no title" label:
732 if ((string)$code === '') {
733 $code = '<i>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', 1) . ']</i> - ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(
734 BackendUtility::getRecordTitle($table, $row), $GLOBALS['BE_USER']->uc['titleLen']));
735 } else {
736 $code = htmlspecialchars(GeneralUtility::fixed_lgd_cs($code, $this->fixedL), ENT_QUOTES, 'UTF-8', FALSE);
737 if ($code != htmlspecialchars($origCode)) {
738 $code = '<span title="' . htmlspecialchars($origCode, ENT_QUOTES, 'UTF-8', FALSE) . '">' . $code . '</span>';
739 }
740 }
741 switch ((string) $this->clickTitleMode) {
742 case 'edit':
743 // If the listed table is 'pages' we have to request the permission settings for each page:
744 if ($table == 'pages') {
745 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
746 $permsEdit = $localCalcPerms & 2;
747 } else {
748 $permsEdit = $this->calcPerms & 16;
749 }
750 // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
751 if ($permsEdit) {
752 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
753 $code = '<a href="#" onclick="' . htmlspecialchars(
754 BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('edit', TRUE) . '">' . $code . '</a>';
755 }
756 break;
757 case 'show':
758 // "Show" link (only pages and tt_content elements)
759 if ($table == 'pages' || $table == 'tt_content') {
760 $code = '<a href="#" onclick="' . htmlspecialchars(
761 BackendUtility::viewOnClick(($table == 'tt_content' ? $this->id . '#' . $row['uid'] : $row['uid']))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . $code . '</a>';
762 }
763 break;
764 case 'info':
765 // "Info": (All records)
766 $code = '<a href="#" onclick="' . htmlspecialchars(('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;')) . '" title="' . $GLOBALS['LANG']->getLL('showInfo', TRUE) . '">' . $code . '</a>';
767 break;
768 default:
769 // Output the label now:
770 if ($table == 'pages') {
771 $code = '<a href="' . htmlspecialchars($this->listURL($uid, '', 'firstElementNumber')) . '" onclick="setHighlight(' . $uid . ')">' . $code . '</a>';
772 } else {
773 $code = $this->linkUrlMail($code, $origCode);
774 }
775 }
776 return $code;
777 }
778
779 /**
780 * Wrapping input code in link to URL or email if $testString is either.
781 *
782 * @param string $code code to wrap
783 * @param string $testString String which is tested for being a URL or email and which will be used for the link if so.
784 * @return string Link-Wrapped $code value, if $testString was URL or email.
785 * @todo Define visibility
786 */
787 public function linkUrlMail($code, $testString) {
788 // Check for URL:
789 $schema = parse_url($testString);
790 if ($schema['scheme'] && GeneralUtility::inList('http,https,ftp', $schema['scheme'])) {
791 return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
792 }
793 // Check for email:
794 if (GeneralUtility::validEmail($testString)) {
795 return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
796 }
797 // Return if nothing else...
798 return $code;
799 }
800
801 /**
802 * Creates the URL to this script, including all relevant GPvars
803 * Fixed GPvars are id, table, imagemode, returnUrl, search_field, search_levels and showLimit
804 * The GPvars "sortField" and "sortRev" are also included UNLESS they are found in the $exclList variable.
805 *
806 * @param string $altId Alternative id value. Enter blank string for the current id ($this->id)
807 * @param string $table Tablename to display. Enter "-1" for the current table.
808 * @param string $exclList Commalist of fields NOT to include ("sortField", "sortRev" or "firstElementNumber")
809 * @return string URL
810 * @todo Define visibility
811 */
812 public function listURL($altId = '', $table = -1, $exclList = '') {
813 $urlParameters = array();
814 if ((string)$altId !== '') {
815 $urlParameters['id'] = $altId;
816 } else {
817 $urlParameters['id'] = $this->id;
818 }
819 if ($table === -1) {
820 $urlParameters['table'] = $this->table;
821 } else {
822 $urlParameters['table'] = $table;
823 }
824 if ($this->thumbs) {
825 $urlParameters['imagemode'] = $this->thumbs;
826 }
827 if ($this->returnUrl) {
828 $urlParameters['returnUrl'] = $this->returnUrl;
829 }
830 if ($this->searchString) {
831 $urlParameters['search_field'] = $this->searchString;
832 }
833 if ($this->searchLevels) {
834 $urlParameters['search_levels'] = $this->searchLevels;
835 }
836 if ($this->showLimit) {
837 $urlParameters['showLimit'] = $this->showLimit;
838 }
839 if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
840 $urlParameters['pointer'] = $this->firstElementNumber;
841 }
842 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
843 $urlParameters['sortField'] = $this->sortField;
844 }
845 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
846 $urlParameters['sortRev'] = $this->sortRev;
847 }
848
849 $urlParameters = array_merge_recursive($urlParameters, $this->overrideUrlParameters);
850
851 return BackendUtility::getModuleUrl(GeneralUtility::_GP('M'), $urlParameters);
852 }
853
854 /**
855 * Returns "requestUri" - which is basically listURL
856 *
857 * @return string Content of ->listURL()
858 * @todo Define visibility
859 */
860 public function requestUri() {
861 return $this->listURL();
862 }
863
864 /**
865 * Makes the list of fields to select for a table
866 *
867 * @param string $table Table name
868 * @param boolean $dontCheckUser If set, users access to the field (non-exclude-fields) is NOT checked.
869 * @param boolean $addDateFields If set, also adds crdate and tstamp fields (note: they will also be added if user is admin or dontCheckUser is set)
870 * @return array Array, where values are fieldnames to include in query
871 * @todo Define visibility
872 */
873 public function makeFieldList($table, $dontCheckUser = 0, $addDateFields = 0) {
874 // Init fieldlist array:
875 $fieldListArr = array();
876 // Check table:
877 if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
878 if (isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
879 // Traverse configured columns and add them to field array, if available for user.
880 foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fieldValue) {
881 if ($dontCheckUser || (!$fieldValue['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $fN)) && $fieldValue['config']['type'] != 'passthrough') {
882 $fieldListArr[] = $fN;
883 }
884 }
885
886 $fieldListArr[] = 'uid';
887 $fieldListArr[] = 'pid';
888
889 // Add date fields
890 if ($dontCheckUser || $GLOBALS['BE_USER']->isAdmin() || $addDateFields) {
891 if ($GLOBALS['TCA'][$table]['ctrl']['tstamp']) {
892 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['tstamp'];
893 }
894 if ($GLOBALS['TCA'][$table]['ctrl']['crdate']) {
895 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['crdate'];
896 }
897 }
898 // Add more special fields:
899 if ($dontCheckUser || $GLOBALS['BE_USER']->isAdmin()) {
900 if ($GLOBALS['TCA'][$table]['ctrl']['cruser_id']) {
901 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['cruser_id'];
902 }
903 if ($GLOBALS['TCA'][$table]['ctrl']['sortby']) {
904 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
905 }
906 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('version') && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
907 $fieldListArr[] = 't3ver_id';
908 $fieldListArr[] = 't3ver_state';
909 $fieldListArr[] = 't3ver_wsid';
910 }
911 }
912 } else {
913 GeneralUtility::sysLog(sprintf('$TCA is broken for the table "%s": no required "columns" entry in $TCA.', $table), 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
914 }
915 }
916 return $fieldListArr;
917 }
918
919 /**
920 * Creates an instance of \TYPO3\CMS\Backend\Tree\View\PageTreeView which will select a page
921 * tree to $depth and return the object. In that object we will find the ids of the tree.
922 *
923 * @param integer $id Page id.
924 * @param integer $depth Depth to go down.
925 * @param string $perms_clause Select clause
926 * @return \TYPO3\CMS\Backend\Tree\View\PageTreeView instance with created list of ids.
927 * @todo Define visibility
928 * @deprecated Deprecated since 6.2, will be removed 2 versions later
929 */
930 public function getTreeObject($id, $depth, $perms_clause) {
931 GeneralUtility::logDeprecatedFunction();
932 $tree = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Tree\\View\\PageTreeView');
933 $tree->init('AND ' . $perms_clause);
934 $tree->makeHTML = 0;
935 $tree->fieldArray = array('uid', 'php_tree_stop');
936 if ($depth) {
937 $tree->getTree($id, $depth, '');
938 }
939 $tree->ids[] = $id;
940 return $tree;
941 }
942
943 /**
944 * Get all allowed mount pages to be searched in.
945 *
946 * @param integer $id Page id
947 * @param integer $depth Depth to go down
948 * @param string $perms_clause select clause
949 * @return array
950 */
951 protected function getSearchableWebmounts($id, $depth, $perms_clause) {
952 /** @var \TYPO3\CMS\Backend\Tree\View\PageTreeView $tree */
953 $tree = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Tree\\View\\PageTreeView');
954 $tree->init('AND ' . $perms_clause);
955 $tree->makeHTML = 0;
956 $tree->fieldArray = array('uid', 'php_tree_stop');
957 $idList = array();
958
959 $allowedMounts = !$GLOBALS['BE_USER']->isAdmin() && $id === 0
960 ? $GLOBALS['BE_USER']->returnWebmounts()
961 : array($id);
962
963 foreach ($allowedMounts as $allowedMount) {
964 $idList[] = $allowedMount;
965 if ($depth) {
966 $tree->getTree($allowedMount, $depth, '');
967 }
968 $idList = array_merge($idList, $tree->ids);
969 }
970
971 return $idList;
972 }
973
974 /**
975 * Redirects to TCEforms (alt_doc) if a record is just localized.
976 *
977 * @param string $justLocalized String with table, orig uid and language separated by ":
978 * @return void
979 * @todo Define visibility
980 */
981 public function localizationRedirect($justLocalized) {
982 list($table, $orig_uid, $language) = explode(':', $justLocalized);
983 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
984 $localizedRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', $table, $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . (int)$language . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$orig_uid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table));
985 if (is_array($localizedRecord)) {
986 // Create parameters and finally run the classic page module for creating a new page translation
987 $url = substr($this->listURL(), strlen($this->backPath));
988 $params = '&edit[' . $table . '][' . $localizedRecord['uid'] . ']=edit';
989 $returnUrl = '&returnUrl=' . rawurlencode($url);
990 $location = $GLOBALS['BACK_PATH'] . 'alt_doc.php?' . $params . $returnUrl;
991 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($location);
992 }
993 }
994 }
995
996 /**
997 * Set URL parameters to override or add in the listUrl() method.
998 *
999 * @param array $urlParameters
1000 * @return void
1001 */
1002 public function setOverrideUrlParameters(array $urlParameters) {
1003 $this->overrideUrlParameters = $urlParameters;
1004 }
1005
1006 }