[FEATURE] High-res TYPO3 logo in topbar
[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 textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 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 * Initializes the list generation
295 *
296 * @param integer $id Page id for which the list is rendered. Must be >= 0
297 * @param string $table Tablename - if extended mode where only one table is listed at a time.
298 * @param integer $pointer Browsing pointer.
299 * @param string $search Search word, if any
300 * @param integer $levels Number of levels to search down the page tree
301 * @param integer $showLimit Limit of records to be listed.
302 * @return void
303 * @todo Define visibility
304 */
305 public function start($id, $table, $pointer, $search = '', $levels = '', $showLimit = 0) {
306 // Setting internal variables:
307 // sets the parent id
308 $this->id = intval($id);
309 if ($GLOBALS['TCA'][$table]) {
310 // Setting single table mode, if table exists:
311 $this->table = $table;
312 }
313 $this->firstElementNumber = $pointer;
314 $this->searchString = trim($search);
315 $this->searchLevels = trim($levels);
316 $this->showLimit = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($showLimit, 0, 10000);
317 // Setting GPvars:
318 $this->csvOutput = GeneralUtility::_GP('csv') ? TRUE : FALSE;
319 $this->sortField = GeneralUtility::_GP('sortField');
320 $this->sortRev = GeneralUtility::_GP('sortRev');
321 $this->displayFields = GeneralUtility::_GP('displayFields');
322 $this->duplicateField = GeneralUtility::_GP('duplicateField');
323 if (GeneralUtility::_GP('justLocalized')) {
324 $this->localizationRedirect(GeneralUtility::_GP('justLocalized'));
325 }
326 // Init dynamic vars:
327 $this->counter = 0;
328 $this->JScode = '';
329 $this->HTMLcode = '';
330 // Limits
331 if (isset($this->modTSconfig['properties']['itemsLimitPerTable'])) {
332 $this->itemsLimitPerTable = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(intval($this->modTSconfig['properties']['itemsLimitPerTable']), 1, 10000);
333 }
334 if (isset($this->modTSconfig['properties']['itemsLimitSingleTable'])) {
335 $this->itemsLimitSingleTable = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(intval($this->modTSconfig['properties']['itemsLimitSingleTable']), 1, 10000);
336 }
337 // Set search levels:
338 $searchLevels = intval($this->searchLevels);
339 $this->perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
340 // This will hide records from display - it has nothing todo with user rights!!
341 if ($pidList = $GLOBALS['BE_USER']->getTSConfigVal('options.hideRecords.pages')) {
342 if ($pidList = $GLOBALS['TYPO3_DB']->cleanIntList($pidList)) {
343 $this->perms_clause .= ' AND pages.uid NOT IN (' . $pidList . ')';
344 }
345 }
346 // Get configuration of collapsed tables from user uc and merge with sanitized GP vars
347 $this->tablesCollapsed = is_array($GLOBALS['BE_USER']->uc['moduleData']['list']) ? $GLOBALS['BE_USER']->uc['moduleData']['list'] : array();
348 $collapseOverride = GeneralUtility::_GP('collapse');
349 if (is_array($collapseOverride)) {
350 foreach ($collapseOverride as $collapseTable => $collapseValue) {
351 if (is_array($GLOBALS['TCA'][$collapseTable]) && ($collapseValue == 0 || $collapseValue == 1)) {
352 $this->tablesCollapsed[$collapseTable] = $collapseValue;
353 }
354 }
355 // Save modified user uc
356 $GLOBALS['BE_USER']->uc['moduleData']['list'] = $this->tablesCollapsed;
357 $GLOBALS['BE_USER']->writeUC($GLOBALS['BE_USER']->uc);
358 $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
359 if ($returnUrl !== '') {
360 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($returnUrl);
361 }
362 }
363 if ($searchLevels > 0) {
364 $tree = $this->getTreeObject($this->id, $searchLevels, $this->perms_clause);
365 $pidList = implode(',', $GLOBALS['TYPO3_DB']->cleanIntArray($tree->ids));
366 $this->pidSelect = 'pid IN (' . $pidList . ')';
367 } elseif ($searchLevels < 0) {
368 // Search everywhere
369 $this->pidSelect = '1=1';
370 } else {
371 $this->pidSelect = 'pid=' . intval($id);
372 }
373 // Initialize languages:
374 if ($this->localizationView) {
375 $this->initializeLanguages();
376 }
377 }
378
379 /**
380 * Traverses the table(s) to be listed and renders the output code for each:
381 * The HTML is accumulated in $this->HTMLcode
382 * Finishes off with a stopper-gif
383 *
384 * @return void
385 * @todo Define visibility
386 */
387 public function generateList() {
388 // Set page record in header
389 $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id);
390 // Traverse the TCA table array:
391 foreach ($GLOBALS['TCA'] as $tableName => $value) {
392 // Checking if the table should be rendered:
393 // Checks that we see only permitted/requested tables:
394 if ((!$this->table || $tableName == $this->table) && (!$this->tableList || GeneralUtility::inList($this->tableList, $tableName)) && $GLOBALS['BE_USER']->check('tables_select', $tableName)) {
395 // Don't show table if hidden by TCA ctrl section
396 $hideTable = $GLOBALS['TCA'][$tableName]['ctrl']['hideTable'] ? TRUE : FALSE;
397 // Don't show table if hidden by pageTSconfig mod.web_list.hideTables
398 if (in_array($tableName, GeneralUtility::trimExplode(',', $this->hideTables))) {
399 $hideTable = TRUE;
400 }
401 // Override previous selection if table is enabled or hidden by TSconfig TCA override mod.web_list.table
402 if (isset($this->tableTSconfigOverTCA[$tableName . '.']['hideTable'])) {
403 $hideTable = $this->tableTSconfigOverTCA[$tableName . '.']['hideTable'] ? TRUE : FALSE;
404 }
405 if ($hideTable) {
406 continue;
407 }
408 // iLimit is set depending on whether we're in single- or multi-table mode
409 if ($this->table) {
410 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']) ? intval($GLOBALS['TCA'][$tableName]['interface']['maxSingleDBListItems']) : $this->itemsLimitSingleTable;
411 } else {
412 $this->iLimit = isset($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']) ? intval($GLOBALS['TCA'][$tableName]['interface']['maxDBListItems']) : $this->itemsLimitPerTable;
413 }
414 if ($this->showLimit) {
415 $this->iLimit = $this->showLimit;
416 }
417 // Setting fields to select:
418 if ($this->allFields) {
419 $fields = $this->makeFieldList($tableName);
420 $fields[] = 'tstamp';
421 $fields[] = 'crdate';
422 $fields[] = '_PATH_';
423 $fields[] = '_CONTROL_';
424 if (is_array($this->setFields[$tableName])) {
425 $fields = array_intersect($fields, $this->setFields[$tableName]);
426 } else {
427 $fields = array();
428 }
429 } else {
430 $fields = array();
431 }
432 // Find ID to use (might be different for "versioning_followPages" tables)
433 if (intval($this->searchLevels) == 0) {
434 $this->pidSelect = 'pid=' . intval($this->id);
435 }
436 // Finally, render the list:
437 $this->HTMLcode .= $this->getTable($tableName, $this->id, implode(',', $fields));
438 }
439 }
440 }
441
442 /**
443 * Creates the search box
444 *
445 * @param boolean $formFields If TRUE, the search box is wrapped in its own form-tags
446 * @return string HTML for the search box
447 * @todo Define visibility
448 */
449 public function getSearchBox($formFields = 1) {
450 // Setting form-elements, if applicable:
451 $formElements = array('', '');
452 if ($formFields) {
453 $formElements = array('<form action="' . htmlspecialchars($this->listURL('', -1, 'firstElementNumber')) . '" method="post">', '</form>');
454 }
455 // Make level selector:
456 $opt = array();
457 $parts = explode('|', $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels'));
458 foreach ($parts as $kv => $label) {
459 $opt[] = '<option value="' . $kv . '"' . ($kv == intval($this->searchLevels) ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
460 }
461 $lMenu = '<select name="search_levels">' . implode('', $opt) . '</select>';
462 // Table with the search box:
463 $content = '<div class="db_list-searchbox-form">
464 ' . $formElements[0] . '
465
466 <!--
467 Search box:
468 -->
469 <table border="0" cellpadding="0" cellspacing="0" id="typo3-dblist-search">
470 <tr>
471 <td><label for="search_field">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchString', TRUE) . '</label></td>
472 <td><input type="text" name="search_field" id="search_field" value="' . htmlspecialchars($this->searchString) . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(10) . ' /></td>
473 <td>' . $lMenu . '</td>
474 <td><input type="submit" name="search" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.search', TRUE) . '" /></td>
475 </tr>
476 <tr>
477 <td><label for="showLimit">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showRecords', TRUE) . ':</label></td>
478 <td colspan="3"><input type="text" name="showLimit" id="showLimit" value="' . htmlspecialchars(($this->showLimit ? $this->showLimit : '')) . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(4) . ' /></td>
479 </tr>
480 </table>
481 ' . $formElements[1] . '</div>';
482 return $content;
483 }
484
485 /**
486 * Creates the display of sys_notes for the page.
487 * Relies on the "sys_note" extension to be loaded.
488 *
489 * @return string HTML for the sys-notes (if any)
490 * @deprecated since 6.0, will be removed two versions later
491 * @todo Define visibility
492 */
493 public function showSysNotesForPage() {
494 GeneralUtility::logDeprecatedFunction();
495 return '';
496 }
497
498 /******************************
499 *
500 * Various helper functions
501 *
502 ******************************/
503 /**
504 * Setting the field names to display in extended list.
505 * Sets the internal variable $this->setFields
506 *
507 * @return void
508 * @todo Define visibility
509 */
510 public function setDispFields() {
511 // Getting from session:
512 $dispFields = $GLOBALS['BE_USER']->getModuleData('list/displayFields');
513 // If fields has been inputted, then set those as the value and push it to session variable:
514 if (is_array($this->displayFields)) {
515 reset($this->displayFields);
516 $tKey = key($this->displayFields);
517 $dispFields[$tKey] = $this->displayFields[$tKey];
518 $GLOBALS['BE_USER']->pushModuleData('list/displayFields', $dispFields);
519 }
520 // Setting result:
521 $this->setFields = $dispFields;
522 }
523
524 /**
525 * Create thumbnail code for record/field
526 *
527 * @param array $row Record array
528 * @param string $table Table (record is from)
529 * @param string $field Field name for which thumbsnail are to be rendered.
530 * @return string HTML for thumbnails, if any.
531 * @todo Define visibility
532 */
533 public function thumbCode($row, $table, $field) {
534 return BackendUtility::thumbCode($row, $table, $field, $this->backPath);
535 }
536
537 /**
538 * Returns the SQL-query array to select the records from a table $table with pid = $id
539 *
540 * @param string $table Table name
541 * @param integer $id Page id (NOT USED! $this->pidSelect is used instead)
542 * @param string $addWhere Additional part for where clause
543 * @param string $fieldList Field list to select, * for all (for "SELECT [fieldlist] FROM ...")
544 * @return array Returns query array
545 * @todo Define visibility
546 */
547 public function makeQueryArray($table, $id, $addWhere = '', $fieldList = '*') {
548 $hookObjectsArr = array();
549 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'])) {
550 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list.inc']['makeQueryArray'] as $classRef) {
551 $hookObjectsArr[] = GeneralUtility::getUserObj($classRef);
552 }
553 }
554 // Set ORDER BY:
555 $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby'] : $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
556 if ($this->sortField) {
557 if (in_array($this->sortField, $this->makeFieldList($table, 1))) {
558 $orderBy = 'ORDER BY ' . $this->sortField;
559 if ($this->sortRev) {
560 $orderBy .= ' DESC';
561 }
562 }
563 }
564 // Set LIMIT:
565 $limit = $this->iLimit ? ($this->firstElementNumber ? $this->firstElementNumber . ',' : '') . ($this->iLimit + 1) : '';
566 // Filtering on displayable pages (permissions):
567 $pC = $table == 'pages' && $this->perms_clause ? ' AND ' . $this->perms_clause : '';
568 // Adding search constraints:
569 $search = $this->makeSearchString($table, $id);
570 // Compiling query array:
571 $queryParts = array(
572 'SELECT' => $fieldList,
573 'FROM' => $table,
574 'WHERE' => $this->pidSelect . ' ' . $pC . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table) . ' ' . $addWhere . ' ' . $search,
575 'GROUPBY' => '',
576 'ORDERBY' => $GLOBALS['TYPO3_DB']->stripOrderBy($orderBy),
577 'LIMIT' => $limit
578 );
579 // Filter out records that are translated, if TSconfig mod.web_list.hideTranslations is set
580 if ((in_array($table, GeneralUtility::trimExplode(',', $this->hideTranslations)) || $this->hideTranslations === '*') && !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) && strcmp($table, 'pages_language_overlay')) {
581 $queryParts['WHERE'] .= ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=0 ';
582 }
583 // Apply hook as requested in http://bugs.typo3.org/view.php?id=4361
584 foreach ($hookObjectsArr as $hookObj) {
585 if (method_exists($hookObj, 'makeQueryArray_post')) {
586 $_params = array(
587 'orderBy' => $orderBy,
588 'limit' => $limit,
589 'pC' => $pC,
590 'search' => $search
591 );
592 $hookObj->makeQueryArray_post($queryParts, $this, $table, $id, $addWhere, $fieldList, $_params);
593 }
594 }
595 // Return query:
596 return $queryParts;
597 }
598
599 /**
600 * Based on input query array (query for selecting count(*) from a table) it will select the number of records and set the value in $this->totalItems
601 *
602 * @param array $queryParts Query array
603 * @return void
604 * @see makeQueryArray()
605 * @todo Define visibility
606 */
607 public function setTotalItems($queryParts) {
608 $this->totalItems = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $queryParts['FROM'], $queryParts['WHERE']);
609 }
610
611 /**
612 * Creates part of query for searching after a word ($this->searchString)
613 * fields in input table.
614 *
615 * @param string $table Table, in which the fields are being searched.
616 * @param integer $currentPid Page id for the possible search limit. -1 only if called from an old XCLASS.
617 * @return string Returns part of WHERE-clause for searching, if applicable.
618 * @todo Define visibility
619 */
620 public function makeSearchString($table, $currentPid = -1) {
621 $result = '';
622 $currentPid = intval($currentPid);
623 $tablePidField = $table == 'pages' ? 'uid' : 'pid';
624 // Make query, only if table is valid and a search string is actually defined:
625 if ($this->searchString) {
626 $result = ' AND 0=1';
627 $searchableFields = $this->getSearchFields($table);
628 if (count($searchableFields) > 0) {
629 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->searchString)) {
630 $whereParts = array(
631 'uid=' . $this->searchString
632 );
633 foreach ($searchableFields as $fieldName) {
634 if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
635 $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
636 $condition = $fieldName . '=' . $this->searchString;
637 if ($fieldConfig['type'] == 'input' && $fieldConfig['eval'] && GeneralUtility::inList($fieldConfig['eval'], 'int')) {
638 if (is_array($fieldConfig['search']) && in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
639 $condition = '(' . $condition . ' AND ' . $tablePidField . '=' . $currentPid . ')';
640 }
641 $whereParts[] = $condition;
642 } elseif (
643 $fieldConfig['type'] == 'text' ||
644 $fieldConfig['type'] == 'flex' ||
645 ($fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval'])))) {
646 $condition = $fieldName . ' LIKE \'%' . $this->searchString . '%\'';
647 $whereParts[] = $condition;
648 }
649 }
650 }
651 } else {
652 $whereParts = array();
653 $like = '\'%' . $GLOBALS['TYPO3_DB']->quoteStr($GLOBALS['TYPO3_DB']->escapeStrForLike($this->searchString, $table), $table) . '%\'';
654 foreach ($searchableFields as $fieldName) {
655 if (isset($GLOBALS['TCA'][$table]['columns'][$fieldName])) {
656 $fieldConfig = &$GLOBALS['TCA'][$table]['columns'][$fieldName]['config'];
657 $format = 'LCASE(%s) LIKE LCASE(%s)';
658 if (is_array($fieldConfig['search'])) {
659 if (in_array('case', $fieldConfig['search'])) {
660 $format = '%s LIKE %s';
661 }
662 if (in_array('pidonly', $fieldConfig['search']) && $currentPid > 0) {
663 $format = '(' . $format . ' AND ' . $tablePidField . '=' . $currentPid . ')';
664 }
665 if ($fieldConfig['search']['andWhere']) {
666 $format = '((' . $fieldConfig['search']['andWhere'] . ') AND (' . $format . '))';
667 }
668 }
669 if ($fieldConfig['type'] == 'text' || $fieldConfig['type'] == 'flex' || $fieldConfig['type'] == 'input' && (!$fieldConfig['eval'] || !preg_match('/date|time|int/', $fieldConfig['eval']))) {
670 $whereParts[] = sprintf($format, $fieldName, $like);
671 }
672 }
673 }
674 }
675 // If search-fields were defined (and there always are) we create the query:
676 if (count($whereParts)) {
677 $result = ' AND (' . implode(' OR ', $whereParts) . ')';
678 }
679 }
680 }
681 return $result;
682 }
683
684 /**
685 * Fetches a list of fields to use in the Backend search for the given table.
686 *
687 * @param string $tableName
688 * @return array
689 */
690 protected function getSearchFields($tableName) {
691 $fieldArray = array();
692 $fieldListWasSet = FALSE;
693 // Get fields from ctrl section of TCA first
694 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['searchFields'])) {
695 $fieldArray = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$tableName]['ctrl']['searchFields'], TRUE);
696 $fieldListWasSet = TRUE;
697 }
698 // Call hook to add or change the list
699 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'])) {
700 $hookParameters = array(
701 'tableHasSearchConfiguration' => $fieldListWasSet,
702 'tableName' => $tableName,
703 'searchFields' => &$fieldArray,
704 'searchString' => $this->searchString
705 );
706 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['mod_list']['getSearchFieldList'] as $hookFunction) {
707 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
708 }
709 }
710 return $fieldArray;
711 }
712
713 /**
714 * Returns the title (based on $code) of a table ($table) with the proper link around. For headers over tables.
715 * The link will cause the display of all extended mode or not for the table.
716 *
717 * @param string $table Table name
718 * @param string $code Table label
719 * @return string The linked table label
720 * @todo Define visibility
721 */
722 public function linkWrapTable($table, $code) {
723 if ($this->table != $table) {
724 return '<a href="' . htmlspecialchars($this->listURL('', $table, 'firstElementNumber')) . '">' . $code . '</a>';
725 } else {
726 return '<a href="' . htmlspecialchars($this->listURL('', '', 'sortField,sortRev,table,firstElementNumber')) . '">' . $code . '</a>';
727 }
728 }
729
730 /**
731 * 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...)
732 *
733 * @param string $table Table name
734 * @param integer $uid Item uid
735 * @param string $code Item title (not htmlspecialchars()'ed yet)
736 * @param array $row Item row
737 * @return string The item title. Ready for HTML output (is htmlspecialchars()'ed)
738 * @todo Define visibility
739 */
740 public function linkWrapItems($table, $uid, $code, $row) {
741 $origCode = $code;
742 // If the title is blank, make a "no title" label:
743 if (!strcmp($code, '')) {
744 $code = '<i>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', 1) . ']</i> - ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(
745 BackendUtility::getRecordTitle($table, $row), $GLOBALS['BE_USER']->uc['titleLen']));
746 } else {
747 $code = htmlspecialchars(GeneralUtility::fixed_lgd_cs($code, $this->fixedL), ENT_QUOTES, 'UTF-8', FALSE);
748 if ($code != htmlspecialchars($origCode)) {
749 $code = '<span title="' . htmlspecialchars($origCode, ENT_QUOTES, 'UTF-8', FALSE) . '">' . $code . '</span>';
750 }
751 }
752 switch ((string) $this->clickTitleMode) {
753 case 'edit':
754 // If the listed table is 'pages' we have to request the permission settings for each page:
755 if ($table == 'pages') {
756 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $row['uid']));
757 $permsEdit = $localCalcPerms & 2;
758 } else {
759 $permsEdit = $this->calcPerms & 16;
760 }
761 // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
762 if ($permsEdit) {
763 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
764 $code = '<a href="#" onclick="' . htmlspecialchars(
765 BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('edit', TRUE) . '">' . $code . '</a>';
766 }
767 break;
768 case 'show':
769 // "Show" link (only pages and tt_content elements)
770 if ($table == 'pages' || $table == 'tt_content') {
771 $code = '<a href="#" onclick="' . htmlspecialchars(
772 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>';
773 }
774 break;
775 case 'info':
776 // "Info": (All records)
777 $code = '<a href="#" onclick="' . htmlspecialchars(('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;')) . '" title="' . $GLOBALS['LANG']->getLL('showInfo', TRUE) . '">' . $code . '</a>';
778 break;
779 default:
780 // Output the label now:
781 if ($table == 'pages') {
782 $code = '<a href="' . htmlspecialchars($this->listURL($uid, '', 'firstElementNumber')) . '" onclick="setHighlight(' . $uid . ')">' . $code . '</a>';
783 } else {
784 $code = $this->linkUrlMail($code, $origCode);
785 }
786 }
787 return $code;
788 }
789
790 /**
791 * Wrapping input code in link to URL or email if $testString is either.
792 *
793 * @param string $code code to wrap
794 * @param string $testString String which is tested for being a URL or email and which will be used for the link if so.
795 * @return string Link-Wrapped $code value, if $testString was URL or email.
796 * @todo Define visibility
797 */
798 public function linkUrlMail($code, $testString) {
799 // Check for URL:
800 $schema = parse_url($testString);
801 if ($schema['scheme'] && GeneralUtility::inList('http,https,ftp', $schema['scheme'])) {
802 return '<a href="' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
803 }
804 // Check for email:
805 if (GeneralUtility::validEmail($testString)) {
806 return '<a href="mailto:' . htmlspecialchars($testString) . '" target="_blank">' . $code . '</a>';
807 }
808 // Return if nothing else...
809 return $code;
810 }
811
812 /**
813 * Creates the URL to this script, including all relevant GPvars
814 * Fixed GPvars are id, table, imagemode, returlUrl, search_field, search_levels and showLimit
815 * The GPvars "sortField" and "sortRev" are also included UNLESS they are found in the $exclList variable.
816 *
817 * @param string $altId Alternative id value. Enter blank string for the current id ($this->id)
818 * @param string $table Tablename to display. Enter "-1" for the current table.
819 * @param string $exclList Commalist of fields NOT to include ("sortField", "sortRev" or "firstElementNumber")
820 * @return string URL
821 * @todo Define visibility
822 */
823 public function listURL($altId = '', $table = -1, $exclList = '') {
824 $urlParameters = array();
825 if (strcmp($altId, '')) {
826 $urlParameters['id'] = $altId;
827 } else {
828 $urlParameters['id'] = $this->id;
829 }
830 if ($table === -1) {
831 $urlParameters['table'] = $this->table;
832 } else {
833 $urlParameters['table'] = $table;
834 }
835 if ($this->thumbs) {
836 $urlParameters['imagemode'] = $this->thumbs;
837 }
838 if ($this->returnUrl) {
839 $urlParameters['returnUrl'] = $this->returnUrl;
840 }
841 if ($this->searchString) {
842 $urlParameters['search_field'] = $this->searchString;
843 }
844 if ($this->searchLevels) {
845 $urlParameters['search_levels'] = $this->searchLevels;
846 }
847 if ($this->showLimit) {
848 $urlParameters['showLimit'] = $this->showLimit;
849 }
850 if ((!$exclList || !GeneralUtility::inList($exclList, 'firstElementNumber')) && $this->firstElementNumber) {
851 $urlParameters['pointer'] = $this->firstElementNumber;
852 }
853 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortField')) && $this->sortField) {
854 $urlParameters['sortField'] = $this->sortField;
855 }
856 if ((!$exclList || !GeneralUtility::inList($exclList, 'sortRev')) && $this->sortRev) {
857 $urlParameters['sortRev'] = $this->sortRev;
858 }
859 return BackendUtility::getModuleUrl('web_list', $urlParameters);
860 }
861
862 /**
863 * Returns "requestUri" - which is basically listURL
864 *
865 * @return string Content of ->listURL()
866 * @todo Define visibility
867 */
868 public function requestUri() {
869 return $this->listURL();
870 }
871
872 /**
873 * Makes the list of fields to select for a table
874 *
875 * @param string $table Table name
876 * @param boolean $dontCheckUser If set, users access to the field (non-exclude-fields) is NOT checked.
877 * @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)
878 * @return array Array, where values are fieldnames to include in query
879 * @todo Define visibility
880 */
881 public function makeFieldList($table, $dontCheckUser = 0, $addDateFields = 0) {
882 // Init fieldlist array:
883 $fieldListArr = array();
884 // Check table:
885 if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
886 if (isset($GLOBALS['TCA'][$table]['columns']) && is_array($GLOBALS['TCA'][$table]['columns'])) {
887 // Traverse configured columns and add them to field array, if available for user.
888 foreach ($GLOBALS['TCA'][$table]['columns'] as $fN => $fieldValue) {
889 if ($dontCheckUser || (!$fieldValue['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $fN)) && $fieldValue['config']['type'] != 'passthrough') {
890 $fieldListArr[] = $fN;
891 }
892 }
893
894 $fieldListArr[] = 'uid';
895 $fieldListArr[] = 'pid';
896
897 // Add date fields
898 if ($dontCheckUser || $GLOBALS['BE_USER']->isAdmin() || $addDateFields) {
899 if ($GLOBALS['TCA'][$table]['ctrl']['tstamp']) {
900 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['tstamp'];
901 }
902 if ($GLOBALS['TCA'][$table]['ctrl']['crdate']) {
903 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['crdate'];
904 }
905 }
906 // Add more special fields:
907 if ($dontCheckUser || $GLOBALS['BE_USER']->isAdmin()) {
908 if ($GLOBALS['TCA'][$table]['ctrl']['cruser_id']) {
909 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['cruser_id'];
910 }
911 if ($GLOBALS['TCA'][$table]['ctrl']['sortby']) {
912 $fieldListArr[] = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
913 }
914 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
915 $fieldListArr[] = 't3ver_id';
916 $fieldListArr[] = 't3ver_state';
917 $fieldListArr[] = 't3ver_wsid';
918 }
919 }
920 } else {
921 GeneralUtility::sysLog(sprintf('$TCA is broken for the table "%s": no required "columns" entry in $TCA.', $table), 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
922 }
923 }
924 return $fieldListArr;
925 }
926
927 /**
928 * Creates an instance of \TYPO3\CMS\Backend\Tree\View\PageTreeView which will select a page
929 * tree to $depth and return the object. In that object we will find the ids of the tree.
930 *
931 * @param integer $id Page id.
932 * @param integer $depth Depth to go down.
933 * @param string $perms_clause Select clause
934 * @return \TYPO3\CMS\Backend\Tree\View\PageTreeView instance with created list of ids.
935 * @todo Define visibility
936 */
937 public function getTreeObject($id, $depth, $perms_clause) {
938 $tree = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Tree\\View\\PageTreeView');
939 $tree->init('AND ' . $perms_clause);
940 $tree->makeHTML = 0;
941 $tree->fieldArray = array('uid', 'php_tree_stop');
942 if ($depth) {
943 $tree->getTree($id, $depth, '');
944 }
945 $tree->ids[] = $id;
946 return $tree;
947 }
948
949 /**
950 * Redirects to TCEforms (alt_doc) if a record is just localized.
951 *
952 * @param string $justLocalized String with table, orig uid and language separated by ":
953 * @return void
954 * @todo Define visibility
955 */
956 public function localizationRedirect($justLocalized) {
957 list($table, $orig_uid, $language) = explode(':', $justLocalized);
958 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
959 $localizedRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', $table, $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . intval($language) . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . intval($orig_uid) . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table));
960 if (is_array($localizedRecord)) {
961 // Create parameters and finally run the classic page module for creating a new page translation
962 $url = substr($this->listURL(), strlen($this->backPath));
963 $params = '&edit[' . $table . '][' . $localizedRecord['uid'] . ']=edit';
964 $returnUrl = '&returnUrl=' . rawurlencode($url);
965 $location = $GLOBALS['BACK_PATH'] . 'alt_doc.php?' . $params . $returnUrl;
966 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($location);
967 }
968 }
969 }
970
971 }