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