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