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