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