6c496abf20b0f22180d5ba2284d18bd0c22b3324
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Database / QueryView.php
1 <?php
2 namespace TYPO3\CMS\Core\Database;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19
20 /**
21 * Class used in module tools/dbint (advanced search) and which may hold code specific for that module
22 * However the class has a general principle in it which may be used in the web/export module.
23 */
24 class QueryView {
25
26 /**
27 * @var string
28 */
29 public $storeList = 'search_query_smallparts,search_result_labels,labels_noprefix,show_deleted,queryConfig,queryTable,queryFields,queryLimit,queryOrder,queryOrderDesc,queryOrder2,queryOrder2Desc,queryGroup,search_query_makeQuery';
30
31 /**
32 * @var string
33 */
34 public $downloadScript = 'index.php';
35
36 /**
37 * @var int
38 */
39 public $formW = 48;
40
41 /**
42 * @var int
43 */
44 public $noDownloadB = 0;
45
46 /**
47 * @var array
48 */
49 public $hookArray = array();
50
51 /**
52 * @var string
53 */
54 protected $formName = '';
55
56 /**
57 * constructor
58 */
59 public function __construct() {
60 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_t3lib_fullsearch.xlf');
61 }
62
63 /**
64 * Get form
65 *
66 * @return string
67 */
68 public function form() {
69 return '
70 <div class="form-group">
71 <input placeholder="Search Word" class="form-control" type="search" name="SET[sword]" value="' . htmlspecialchars($GLOBALS['SOBE']->MOD_SETTINGS['sword']) . '">
72 </div>
73 <div class="form-group">
74 <input class="btn btn-default" type="submit" name="submit" value="Search All Records">
75 </div>
76 ';
77 }
78
79 /**
80 * Make store control
81 *
82 * @return string
83 */
84 public function makeStoreControl() {
85 // Load/Save
86 $storeArray = $this->initStoreArray();
87
88 $opt = array();
89 foreach ($storeArray as $k => $v) {
90 $opt[] = '<option value="' . $k . '">' . htmlspecialchars($v) . '</option>';
91 }
92 // Actions:
93 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sys_action') && $GLOBALS['BE_USER']->isAdmin()) {
94 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_action', 'type=2', '', 'title');
95 $opt[] = '<option value="0">__Save to Action:__</option>';
96 foreach($rows as $row) {
97 $opt[] = '<option value="-' . $row['uid'] . '">' . htmlspecialchars(($row['title'] . ' [' . $row['uid'] . ']')) . '</option>';
98 }
99 }
100 return '<div class="load-queries">
101 <div class="form-inline">
102 <div class="form-group">
103 <select class="form-control" name="storeControl[STORE]" onChange="document.forms[0][\'storeControl[title]\'].value= this.options[this.selectedIndex].value!=0 ? this.options[this.selectedIndex].text : \'\';">' . implode(LF, $opt) . '</select>
104 <input class="btn btn-default" type="submit" name="storeControl[LOAD]" value="Load">
105 </div>
106 </div>
107 <div class="form-inline">
108 <div class="form-group">
109 <input name="storeControl[title]" value="" type="text" max="80" class="form-control">
110 <input class="btn btn-default" type="submit" name="storeControl[SAVE]" value="Save" onClick="if (document.forms[0][\'storeControl[STORE]\'].options[document.forms[0][\'storeControl[STORE]\'].selectedIndex].value<0) return confirm(\'Are you sure you want to overwrite the existing query in this action?\');">
111 <input class="btn btn-default" type="submit" name="storeControl[REMOVE]" value="Remove">
112 </div>
113 </div>
114 </div>';
115 }
116
117 /**
118 * Init store array
119 *
120 * @return array
121 */
122 public function initStoreArray() {
123 $storeArray = array(
124 '0' => '[New]'
125 );
126 $savedStoreArray = unserialize($GLOBALS['SOBE']->MOD_SETTINGS['storeArray']);
127 if (is_array($savedStoreArray)) {
128 $storeArray = array_merge($storeArray, $savedStoreArray);
129 }
130 return $storeArray;
131 }
132
133 /**
134 * Clean store query configs
135 *
136 * @param array $storeQueryConfigs
137 * @param array $storeArray
138 * @return array
139 */
140 public function cleanStoreQueryConfigs($storeQueryConfigs, $storeArray) {
141 if (is_array($storeQueryConfigs)) {
142 foreach ($storeQueryConfigs as $k => $v) {
143 if (!isset($storeArray[$k])) {
144 unset($storeQueryConfigs[$k]);
145 }
146 }
147 }
148 return $storeQueryConfigs;
149 }
150
151 /**
152 * Add to store query configs
153 *
154 * @param array $storeQueryConfigs
155 * @param int $index
156 * @return array
157 */
158 public function addToStoreQueryConfigs($storeQueryConfigs, $index) {
159 $keyArr = explode(',', $this->storeList);
160 $storeQueryConfigs[$index] = array();
161 foreach ($keyArr as $k) {
162 $storeQueryConfigs[$index][$k] = $GLOBALS['SOBE']->MOD_SETTINGS[$k];
163 }
164 return $storeQueryConfigs;
165 }
166
167 /**
168 * Save query in action
169 *
170 * @param int $uid
171 * @return int
172 */
173 public function saveQueryInAction($uid) {
174 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sys_action')) {
175 $keyArr = explode(',', $this->storeList);
176 $saveArr = array();
177 foreach ($keyArr as $k) {
178 $saveArr[$k] = $GLOBALS['SOBE']->MOD_SETTINGS[$k];
179 }
180 $qOK = 0;
181 // Show query
182 if ($saveArr['queryTable']) {
183 /** @var \TYPO3\CMS\Core\Database\QueryGenerator */
184 $qGen = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\QueryGenerator::class);
185 $qGen->init('queryConfig', $saveArr['queryTable']);
186 $qGen->makeSelectorTable($saveArr);
187 $qGen->enablePrefix = 1;
188 $qString = $qGen->getQuery($qGen->queryConfig);
189 $qCount = $GLOBALS['TYPO3_DB']->SELECTquery('count(*)', $qGen->table, $qString . BackendUtility::deleteClause($qGen->table));
190 $qSelect = $qGen->getSelectQuery($qString);
191 $res = @$GLOBALS['TYPO3_DB']->sql_query($qCount);
192 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
193 $GLOBALS['TYPO3_DB']->sql_free_result($res);
194 $dA = array();
195 $dA['t2_data'] = serialize(array(
196 'qC' => $saveArr,
197 'qCount' => $qCount,
198 'qSelect' => $qSelect,
199 'qString' => $qString
200 ));
201 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_action', 'uid=' . (int)$uid, $dA);
202 $qOK = 1;
203 }
204 }
205 return $qOK;
206 }
207 }
208
209 /**
210 * Load store query configs
211 *
212 * @param array $storeQueryConfigs
213 * @param int $storeIndex
214 * @param array $writeArray
215 * @return array
216 */
217 public function loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray) {
218 if ($storeQueryConfigs[$storeIndex]) {
219 $keyArr = explode(',', $this->storeList);
220 foreach ($keyArr as $k) {
221 $writeArray[$k] = $storeQueryConfigs[$storeIndex][$k];
222 }
223 }
224 return $writeArray;
225 }
226
227 /**
228 * Process store control
229 *
230 * @return string
231 */
232 public function procesStoreControl() {
233 $storeArray = $this->initStoreArray();
234 $storeQueryConfigs = unserialize($GLOBALS['SOBE']->MOD_SETTINGS['storeQueryConfigs']);
235 $storeControl = GeneralUtility::_GP('storeControl');
236 $storeIndex = (int)$storeControl['STORE'];
237 $saveStoreArray = 0;
238 $writeArray = array();
239 if (is_array($storeControl)) {
240 $msg = '';
241 if ($storeControl['LOAD']) {
242 if ($storeIndex > 0) {
243 $writeArray = $this->loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray);
244 $saveStoreArray = 1;
245 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, sprintf($GLOBALS['LANG']->getLL('query_loaded'), htmlspecialchars($storeArray[$storeIndex])));
246 } elseif ($storeIndex < 0 && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sys_action')) {
247 $actionRecord = BackendUtility::getRecord('sys_action', abs($storeIndex));
248 if (is_array($actionRecord)) {
249 $dA = unserialize($actionRecord['t2_data']);
250 $dbSC = array();
251 if (is_array($dA['qC'])) {
252 $dbSC[0] = $dA['qC'];
253 }
254 $writeArray = $this->loadStoreQueryConfigs($dbSC, '0', $writeArray);
255 $saveStoreArray = 1;
256 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, sprintf($GLOBALS['LANG']->getLL('query_from_action_loaded'), htmlspecialchars($actionRecord['title'])));
257 }
258 }
259 } elseif ($storeControl['SAVE']) {
260 if ($storeIndex < 0) {
261 $qOK = $this->saveQueryInAction(abs($storeIndex));
262 if ($qOK) {
263 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $GLOBALS['LANG']->getLL('query_saved'));
264 } else {
265 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $GLOBALS['LANG']->getLL('query_notsaved'), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
266 }
267 } else {
268 if (trim($storeControl['title'])) {
269 if ($storeIndex > 0) {
270 $storeArray[$storeIndex] = $storeControl['title'];
271 } else {
272 $storeArray[] = $storeControl['title'];
273 end($storeArray);
274 $storeIndex = key($storeArray);
275 }
276 $storeQueryConfigs = $this->addToStoreQueryConfigs($storeQueryConfigs, $storeIndex);
277 $saveStoreArray = 1;
278 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $GLOBALS['LANG']->getLL('query_saved'));
279 }
280 }
281 } elseif ($storeControl['REMOVE']) {
282 if ($storeIndex > 0) {
283 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, sprintf($GLOBALS['LANG']->getLL('query_removed'), htmlspecialchars($storeArray[$storeControl['STORE']])));
284 // Removing
285 unset($storeArray[$storeControl['STORE']]);
286 $saveStoreArray = 1;
287 }
288 }
289 if ($flashMessage) {
290 $msg = $flashMessage->render();
291 }
292 }
293 if ($saveStoreArray) {
294 // Making sure, index 0 is not set!
295 unset($storeArray[0]);
296 $writeArray['storeArray'] = serialize($storeArray);
297 $writeArray['storeQueryConfigs'] = serialize($this->cleanStoreQueryConfigs($storeQueryConfigs, $storeArray));
298 $GLOBALS['SOBE']->MOD_SETTINGS = BackendUtility::getModuleData($GLOBALS['SOBE']->MOD_MENU, $writeArray, $GLOBALS['SOBE']->MCONF['name'], 'ses');
299 }
300 return $msg;
301 }
302
303 /**
304 * Query marker
305 *
306 * @return string
307 */
308 public function queryMaker() {
309 $output = '';
310 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3lib_fullsearch'])) {
311 $this->hookArray = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3lib_fullsearch'];
312 }
313 $msg = $this->procesStoreControl();
314 if (!$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableStoreControl']) {
315 $output .= $GLOBALS['SOBE']->doc->section('Load/Save Query', $this->makeStoreControl(), 0, 1);
316 if ($msg) {
317 $output .= '<br />' . $msg;
318 }
319 $output .= $GLOBALS['SOBE']->doc->spacer(20);
320 }
321 // Query Maker:
322 $qGen = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\QueryGenerator::class);
323 $qGen->init('queryConfig', $GLOBALS['SOBE']->MOD_SETTINGS['queryTable']);
324 if ($this->formName) {
325 $qGen->setFormName($this->formName);
326 }
327 $tmpCode = $qGen->makeSelectorTable($GLOBALS['SOBE']->MOD_SETTINGS);
328 $output .= '<div id="query"></div>' . $GLOBALS['SOBE']->doc->section('Make query', $tmpCode, 0, 1);
329 $mQ = $GLOBALS['SOBE']->MOD_SETTINGS['search_query_makeQuery'];
330 // Make form elements:
331 if ($qGen->table && is_array($GLOBALS['TCA'][$qGen->table])) {
332 if ($mQ) {
333 // Show query
334 $qGen->enablePrefix = 1;
335 $qString = $qGen->getQuery($qGen->queryConfig);
336 switch ($mQ) {
337 case 'count':
338 $qExplain = $GLOBALS['TYPO3_DB']->SELECTquery('count(*)', $qGen->table, $qString . BackendUtility::deleteClause($qGen->table));
339 break;
340 default:
341 $qExplain = $qGen->getSelectQuery($qString);
342 if ($mQ == 'explain') {
343 $qExplain = 'EXPLAIN ' . $qExplain;
344 }
345 }
346 if (!$GLOBALS['BE_USER']->userTS['mod.']['dbint.']['disableShowSQLQuery']) {
347 $output .= $GLOBALS['SOBE']->doc->section('SQL query', $this->tableWrap(htmlspecialchars($qExplain)), 0, 1);
348 }
349 $res = @$GLOBALS['TYPO3_DB']->sql_query($qExplain);
350 if ($GLOBALS['TYPO3_DB']->sql_error()) {
351 $out = '<BR><strong>Error:</strong><BR><font color="red"><strong>' . $GLOBALS['TYPO3_DB']->sql_error() . '</strong></font>';
352 $output .= $GLOBALS['SOBE']->doc->section('SQL error', $out, 0, 1);
353 } else {
354 $cPR = $this->getQueryResultCode($mQ, $res, $qGen->table);
355 $GLOBALS['TYPO3_DB']->sql_free_result($res);
356 $output .= $GLOBALS['SOBE']->doc->section($cPR['header'], $cPR['content'], 0, 1);
357 }
358 }
359 }
360 return '<div class="query-builder">' . $output . '</div>';
361 }
362
363 /**
364 * Get query result code
365 *
366 * @param string $mQ
367 * @param bool|\mysqli_result|object $res MySQLi result object / DBAL object
368 * @param string $table
369 * @return string
370 */
371 public function getQueryResultCode($mQ, $res, $table) {
372 $out = '';
373 $cPR = array();
374 switch ($mQ) {
375 case 'count':
376 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
377 $cPR['header'] = 'Count';
378 $cPR['content'] = '<BR><strong>' . $row[0] . '</strong> records selected.';
379 break;
380 case 'all':
381 $rowArr = array();
382 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
383 $rowArr[] = $this->resultRowDisplay($row, $GLOBALS['TCA'][$table], $table);
384 $lrow = $row;
385 }
386 if (is_array($this->hookArray['beforeResultTable'])) {
387 foreach ($this->hookArray['beforeResultTable'] as $_funcRef) {
388 $out .= GeneralUtility::callUserFunction($_funcRef, $GLOBALS['SOBE']->MOD_SETTINGS, $this);
389 }
390 }
391 if (!empty($rowArr)) {
392 $out .= '<table class="table table-striped table-hover">' . $this->resultRowTitles($lrow, $GLOBALS['TCA'][$table], $table) . implode(LF, $rowArr) . '</table>';
393 }
394 if (!$out) {
395 $out = '<div class="alert-info">No rows selected!</div>';
396 }
397 $cPR['header'] = 'Result';
398 $cPR['content'] = $out;
399 break;
400 case 'csv':
401 $rowArr = array();
402 $first = 1;
403 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
404 if ($first) {
405 $rowArr[] = $this->csvValues(array_keys($row), ',', '');
406 $first = 0;
407 }
408 $rowArr[] = $this->csvValues($row, ',', '"', $GLOBALS['TCA'][$table], $table);
409 }
410 if (!empty($rowArr)) {
411 $out .= '<textarea name="whatever" rows="20" wrap="off"' . $GLOBALS['SOBE']->doc->formWidth($this->formW) . ' class="text-monospace">' . htmlspecialchars(implode(LF, $rowArr)) . '</textarea>';
412 if (!$this->noDownloadB) {
413 $out .= '<br><input class="btn btn-default" type="submit" name="download_file" value="Click to download file" onClick="window.location.href=\'' . $this->downloadScript . '\';">';
414 }
415 // Downloads file:
416 if (GeneralUtility::_GP('download_file')) {
417 $filename = 'TYPO3_' . $table . '_export_' . date('dmy-Hi') . '.csv';
418 $mimeType = 'application/octet-stream';
419 header('Content-Type: ' . $mimeType);
420 header('Content-Disposition: attachment; filename=' . $filename);
421 echo implode(CRLF, $rowArr);
422 die;
423 }
424 }
425 if (!$out) {
426 $out = '<em>No rows selected!</em>';
427 }
428 $cPR['header'] = 'Result';
429 $cPR['content'] = $out;
430 break;
431 case 'explain':
432
433 default:
434 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
435 $out .= '<br />' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($row);
436 }
437 $cPR['header'] = 'Explain SQL query';
438 $cPR['content'] = $out;
439 }
440 return $cPR;
441 }
442
443 /**
444 * CSV values
445 *
446 * @param array $row
447 * @param string $delim
448 * @param string $quote
449 * @param array $conf
450 * @param string $table
451 * @return string A single line of CSV
452 */
453 public function csvValues($row, $delim = ',', $quote = '"', $conf = array(), $table = '') {
454 $valueArray = $row;
455 if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels'] && $table) {
456 foreach ($valueArray as $key => $val) {
457 $valueArray[$key] = $this->getProcessedValueExtra($table, $key, $val, $conf, ';');
458 }
459 }
460 return GeneralUtility::csvValues($valueArray, $delim, $quote);
461 }
462
463 /**
464 * Table wrap
465 *
466 * @param string $str
467 * @return string
468 */
469 public function tableWrap($str) {
470 return '<pre>' . $str . '</pre>';
471 }
472
473 /**
474 * Search
475 *
476 * @return string
477 */
478 public function search() {
479 $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
480 $swords = $SET['sword'];
481 $out = '';
482 $limit = 200;
483 if ($swords) {
484 foreach ($GLOBALS['TCA'] as $table => $value) {
485 // Get fields list
486 $conf = $GLOBALS['TCA'][$table];
487 // Avoid querying tables with no columns
488 if (empty($conf['columns'])) {
489 continue;
490 }
491 $fieldsInDatabase = $GLOBALS['TYPO3_DB']->admin_get_fields($table);
492 $list = array_intersect(array_keys($conf['columns']), array_keys($fieldsInDatabase));
493 // Get query
494 $qp = $GLOBALS['TYPO3_DB']->searchQuery(array($swords), $list, $table);
495 // Count:
496 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $table, $qp . BackendUtility::deleteClause($table));
497 if ($count) {
498 $rowArr = array();
499 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,' . $conf['ctrl']['label'], $table, $qp . BackendUtility::deleteClause($table), '', '', $limit);
500 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
501 $rowArr[] = $this->resultRowDisplay($row, $conf, $table);
502 $lrow = $row;
503 }
504 $GLOBALS['TYPO3_DB']->sql_free_result($res);
505 $out .= '<div class="panel panel-default">
506 <div class="panel-heading">' . $GLOBALS['LANG']->sL($conf['ctrl']['title'], TRUE) . ' (' . $count . ')</div>
507 <table class="table table-striped table-hover">' .
508 $this->resultRowTitles($lrow, $conf, $table) .
509 implode(LF, $rowArr) .
510 '</table>
511 </div>';
512 }
513 }
514 }
515 return $out;
516 }
517
518 /**
519 * Result row display
520 *
521 * @param array $row
522 * @param array $conf
523 * @param string $table
524 * @return string
525 */
526 public function resultRowDisplay($row, $conf, $table) {
527 $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
528 $out = '<tr>';
529 foreach ($row as $fieldName => $fieldValue) {
530 if (GeneralUtility::inList($SET['queryFields'], $fieldName) || !$SET['queryFields'] && $fieldName != 'pid' && $fieldName != 'deleted') {
531 if ($SET['search_result_labels']) {
532 $fVnew = $this->getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, '<br />');
533 } else {
534 $fVnew = htmlspecialchars($fieldValue);
535 }
536 $out .= '<td>' . $fVnew . '</td>';
537 }
538 }
539 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
540 $out .= '<td><div class="btn-group">';
541 if (!$row['deleted']) {
542 $out .= '<a class="btn btn-default" href="#" onClick="top.launchView(\'' . $table . '\',' . $row['uid'] . ',\'' . $GLOBALS['BACK_PATH'] . '\');return false;">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-dialog-information') . '</a>';
543 $out .= '<a class="btn btn-default" href="#" onClick="' . htmlspecialchars(BackendUtility::editOnClick($params, '', GeneralUtility::getIndpEnv('REQUEST_URI') . GeneralUtility::implodeArrayForUrl('SET', (array)GeneralUtility::_POST('SET')))) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open') . '</a>';
544 } else {
545 $out .= '<a class="btn btn-default" href="' . GeneralUtility::linkThisUrl(BackendUtility::getModuleUrl('tce_db'), array(
546 ('cmd[' . $table . '][' . $row['uid'] . '][undelete]') => '1',
547 'redirect' => GeneralUtility::linkThisScript(array())
548 )) . BackendUtility::getUrlToken('tceAction') . '">';
549 $out .= \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-restore', array('title' => 'undelete only')) . '</a>';
550 $formEngineParameters = array(
551 'edit[' . $table . '][' . $row['uid'] . ']' => 'edit',
552 'returnUrl' => GeneralUtility::linkThisScript(array())
553 );
554 $redirectUrl = BackendUtility::getModuleUrl('record_edit', $formEngineParameters);
555 $out .= '<a class="btn btn-default" href="' . GeneralUtility::linkThisUrl(BackendUtility::getModuleUrl('tce_db'), array(
556 ('cmd[' . $table . '][' . $row['uid'] . '][undelete]') => '1',
557 'redirect' => $redirectUrl
558 )) . BackendUtility::getUrlToken('tceAction') . '">';
559 $out .= \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-restore-edit', array('title' => 'undelete and edit')) . '</a>';
560 }
561 $_params = array($table => $row);
562 if (is_array($this->hookArray['additionalButtons'])) {
563 foreach ($this->hookArray['additionalButtons'] as $_funcRef) {
564 $out .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
565 }
566 }
567 $out .= '</div></td>
568 </tr>
569 ';
570 return $out;
571 }
572
573 /**
574 * Get processed value extra
575 *
576 * @param string $table
577 * @param string $fieldName
578 * @param string $fieldValue
579 * @param array $conf Not used
580 * @param string $splitString
581 * @return string
582 */
583 public function getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, $splitString) {
584 $out = '';
585 // Analysing the fields in the table.
586 if (is_array($GLOBALS['TCA'][$table])) {
587 $fC = $GLOBALS['TCA'][$table]['columns'][$fieldName];
588 $fields = $fC['config'];
589 $fields['exclude'] = $fC['exclude'];
590 if (is_array($fC) && $fC['label']) {
591 $fields['label'] = preg_replace('/:$/', '', trim($GLOBALS['LANG']->sL($fC['label'])));
592 switch ($fields['type']) {
593 case 'input':
594 if (preg_match('/int|year/i', $fields['eval'])) {
595 $fields['type'] = 'number';
596 } elseif (preg_match('/time/i', $fields['eval'])) {
597 $fields['type'] = 'time';
598 } elseif (preg_match('/date/i', $fields['eval'])) {
599 $fields['type'] = 'date';
600 } else {
601 $fields['type'] = 'text';
602 }
603 break;
604 case 'check':
605 if (!$fields['items']) {
606 $fields['type'] = 'boolean';
607 } else {
608 $fields['type'] = 'binary';
609 }
610 break;
611 case 'radio':
612 $fields['type'] = 'multiple';
613 break;
614 case 'select':
615 $fields['type'] = 'multiple';
616 if ($fields['foreign_table']) {
617 $fields['type'] = 'relation';
618 }
619 if ($fields['special']) {
620 $fields['type'] = 'text';
621 }
622 break;
623 case 'group':
624 $fields['type'] = 'files';
625 if ($fields['internal_type'] == 'db') {
626 $fields['type'] = 'relation';
627 }
628 break;
629 case 'user':
630 case 'flex':
631 case 'passthrough':
632 case 'none':
633 case 'text':
634 default:
635 $fields['type'] = 'text';
636 }
637 } else {
638 $fields['label'] = '[FIELD: ' . $fieldName . ']';
639 switch ($fieldName) {
640 case 'pid':
641 $fields['type'] = 'relation';
642 $fields['allowed'] = 'pages';
643 break;
644 case 'cruser_id':
645 $fields['type'] = 'relation';
646 $fields['allowed'] = 'be_users';
647 break;
648 case 'tstamp':
649
650 case 'crdate':
651 $fields['type'] = 'time';
652 break;
653 default:
654 $fields['type'] = 'number';
655 }
656 }
657 }
658 switch ($fields['type']) {
659 case 'date':
660 if ($fieldValue != -1) {
661 $out = strftime('%e-%m-%Y', $fieldValue);
662 }
663 break;
664 case 'time':
665 if ($fieldValue != -1) {
666 if ($splitString == '<br />') {
667 $out = strftime('%H:%M' . $splitString . '%e-%m-%Y', $fieldValue);
668 } else {
669 $out = strftime('%H:%M %e-%m-%Y', $fieldValue);
670 }
671 }
672 break;
673 case 'multiple':
674 case 'binary':
675 case 'relation':
676 $out = $this->makeValueList($fieldName, $fieldValue, $fields, $table, $splitString);
677 break;
678 case 'boolean':
679 $out = $fieldValue ? 'True' : 'False';
680 break;
681 case 'files':
682 default:
683 $out = htmlspecialchars($fieldValue);
684 }
685 return $out;
686 }
687
688 /**
689 * Get tree list
690 *
691 * @param int $id
692 * @param int $depth
693 * @param int $begin
694 * @param string $perms_clause
695 * @return string
696 */
697 public function getTreeList($id, $depth, $begin = 0, $perms_clause) {
698 $depth = (int)$depth;
699 $begin = (int)$begin;
700 $id = (int)$id;
701 if ($id < 0) {
702 $id = abs($id);
703 }
704 if ($begin == 0) {
705 $theList = $id;
706 } else {
707 $theList = '';
708 }
709 if ($id && $depth > 0) {
710 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid=' . $id . ' ' . BackendUtility::deleteClause('pages') . ' AND ' . $perms_clause);
711 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
712 if ($begin <= 0) {
713 $theList .= ',' . $row['uid'];
714 }
715 if ($depth > 1) {
716 $theList .= $this->getTreeList($row['uid'], $depth - 1, $begin - 1, $perms_clause);
717 }
718 }
719 $GLOBALS['TYPO3_DB']->sql_free_result($res);
720 }
721 return $theList;
722 }
723
724 /**
725 * Make value list
726 *
727 * @param string $fieldName
728 * @param string $fieldValue
729 * @param array $conf
730 * @param string $table
731 * @param string $splitString
732 * @return string
733 */
734 public function makeValueList($fieldName, $fieldValue, $conf, $table, $splitString) {
735 $fieldSetup = $conf;
736 $out = '';
737 if ($fieldSetup['type'] == 'files') {
738 $d = dir(PATH_site . $fieldSetup['uploadfolder']);
739 while (FALSE !== ($entry = $d->read())) {
740 if ($entry == '.' || $entry == '..') {
741 continue;
742 }
743 $fileArray[] = $entry;
744 }
745 $d->close();
746 natcasesort($fileArray);
747 foreach ($fileArray as $fileName) {
748 if (GeneralUtility::inList($fieldValue, $fileName) || $fieldValue == $fileName) {
749 if (!$out) {
750 $out = htmlspecialchars($fileName);
751 } else {
752 $out .= $splitString . htmlspecialchars($fileName);
753 }
754 }
755 }
756 }
757 if ($fieldSetup['type'] == 'multiple') {
758 foreach ($fieldSetup['items'] as $key => $val) {
759 if (substr($val[0], 0, 4) == 'LLL:') {
760 $value = $GLOBALS['LANG']->sL($val[0]);
761 } else {
762 $value = $val[0];
763 }
764 if (GeneralUtility::inList($fieldValue, $val[1]) || $fieldValue == $val[1]) {
765 if (!$out) {
766 $out = htmlspecialchars($value);
767 } else {
768 $out .= $splitString . htmlspecialchars($value);
769 }
770 }
771 }
772 }
773 if ($fieldSetup['type'] == 'binary') {
774 foreach ($fieldSetup['items'] as $Key => $val) {
775 if (substr($val[0], 0, 4) == 'LLL:') {
776 $value = $GLOBALS['LANG']->sL($val[0]);
777 } else {
778 $value = $val[0];
779 }
780 if (!$out) {
781 $out = htmlspecialchars($value);
782 } else {
783 $out .= $splitString . htmlspecialchars($value);
784 }
785 }
786 }
787 if ($fieldSetup['type'] == 'relation') {
788 if ($fieldSetup['items']) {
789 foreach ($fieldSetup['items'] as $key => $val) {
790 if (substr($val[0], 0, 4) == 'LLL:') {
791 $value = $GLOBALS['LANG']->sL($val[0]);
792 } else {
793 $value = $val[0];
794 }
795 if (GeneralUtility::inList($fieldValue, $value) || $fieldValue == $value) {
796 if (!$out) {
797 $out = htmlspecialchars($value);
798 } else {
799 $out .= $splitString . htmlspecialchars($value);
800 }
801 }
802 }
803 }
804 if (stristr($fieldSetup['allowed'], ',')) {
805 $from_table_Arr = explode(',', $fieldSetup['allowed']);
806 $useTablePrefix = 1;
807 if (!$fieldSetup['prepend_tname']) {
808 $checkres = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldName, $table, 'uid ' . BackendUtility::deleteClause($table), ($groupBy = ''), ($orderBy = ''), ($limit = ''));
809 if ($checkres) {
810 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($checkres)) {
811 if (stristr($row[$fieldName], ',')) {
812 $checkContent = explode(',', $row[$fieldName]);
813 foreach ($checkContent as $singleValue) {
814 if (!stristr($singleValue, '_')) {
815 $dontPrefixFirstTable = 1;
816 }
817 }
818 } else {
819 $singleValue = $row[$fieldName];
820 if ($singleValue !== '' && !stristr($singleValue, '_')) {
821 $dontPrefixFirstTable = 1;
822 }
823 }
824 }
825 $GLOBALS['TYPO3_DB']->sql_free_result($checkres);
826 }
827 }
828 } else {
829 $from_table_Arr[0] = $fieldSetup['allowed'];
830 }
831 if ($fieldSetup['prepend_tname']) {
832 $useTablePrefix = 1;
833 }
834 if ($fieldSetup['foreign_table']) {
835 $from_table_Arr[0] = $fieldSetup['foreign_table'];
836 }
837 $counter = 0;
838 foreach ($from_table_Arr as $from_table) {
839 if ($useTablePrefix && !$dontPrefixFirstTable && $counter != 1 || $counter == 1) {
840 $tablePrefix = $from_table . '_';
841 }
842 $counter = 1;
843 if (is_array($GLOBALS['TCA'][$from_table])) {
844 $labelField = $GLOBALS['TCA'][$from_table]['ctrl']['label'];
845 $altLabelField = $GLOBALS['TCA'][$from_table]['ctrl']['label_alt'];
846 if ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items']) {
847 foreach ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items'] as $labelArray) {
848 if (substr($labelArray[0], 0, 4) == 'LLL:') {
849 $labelFieldSelect[$labelArray[1]] = $GLOBALS['LANG']->sL($labelArray[0]);
850 } else {
851 $labelFieldSelect[$labelArray[1]] = $labelArray[0];
852 }
853 }
854 $useSelectLabels = 1;
855 }
856 if ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items']) {
857 foreach ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items'] as $altLabelArray) {
858 if (substr($altLabelArray[0], 0, 4) == 'LLL:') {
859 $altLabelFieldSelect[$altLabelArray[1]] = $GLOBALS['LANG']->sL($altLabelArray[0]);
860 } else {
861 $altLabelFieldSelect[$altLabelArray[1]] = $altLabelArray[0];
862 }
863 }
864 $useAltSelectLabels = 1;
865 }
866 $altLabelFieldSelect = $altLabelField ? ',' . $altLabelField : '';
867 $select_fields = 'uid,' . $labelField . $altLabelFieldSelect;
868 if (!$GLOBALS['BE_USER']->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
869 $webMounts = $GLOBALS['BE_USER']->returnWebmounts();
870 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
871 $webMountPageTree = '';
872 foreach ($webMounts as $key => $val) {
873 if ($webMountPageTree) {
874 $webMountPageTreePrefix = ',';
875 }
876 $webMountPageTree .= $webMountPageTreePrefix . $this->getTreeList($val, 999, ($begin = 0), $perms_clause);
877 }
878 if ($from_table == 'pages') {
879 $where_clause = 'uid IN (' . $webMountPageTree . ') ' . BackendUtility::deleteClause($from_table) . ' AND ' . $perms_clause;
880 } else {
881 $where_clause = 'pid IN (' . $webMountPageTree . ') ' . BackendUtility::deleteClause($from_table);
882 }
883 } else {
884 $where_clause = 'uid' . BackendUtility::deleteClause($from_table);
885 }
886 $orderBy = 'uid';
887 if (!$this->tableArray[$from_table]) {
888 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select_fields, $from_table, $where_clause, ($groupBy = ''), $orderBy, ($limit = ''));
889 $this->tableArray[$from_table] = array();
890 }
891 if ($res) {
892 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
893 $this->tableArray[$from_table][] = $row;
894 }
895 $GLOBALS['TYPO3_DB']->sql_free_result($res);
896 }
897 foreach ($this->tableArray[$from_table] as $key => $val) {
898 $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] = $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] == 1 ? 'on' : $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'];
899 $prefixString = $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] == 'on' ? '' : ' [' . $tablePrefix . $val['uid'] . '] ';
900 if (GeneralUtility::inList($fieldValue, $tablePrefix . $val['uid']) || $fieldValue == $tablePrefix . $val['uid']) {
901 if ($useSelectLabels) {
902 if (!$out) {
903 $out = htmlspecialchars($prefixString . $labelFieldSelect[$val[$labelField]]);
904 } else {
905 $out .= $splitString . htmlspecialchars(($prefixString . $labelFieldSelect[$val[$labelField]]));
906 }
907 } elseif ($val[$labelField]) {
908 if (!$out) {
909 $out = htmlspecialchars($prefixString . $val[$labelField]);
910 } else {
911 $out .= $splitString . htmlspecialchars(($prefixString . $val[$labelField]));
912 }
913 } elseif ($useAltSelectLabels) {
914 if (!$out) {
915 $out = htmlspecialchars($prefixString . $altLabelFieldSelect[$val[$altLabelField]]);
916 } else {
917 $out .= $splitString . htmlspecialchars(($prefixString . $altLabelFieldSelect[$val[$altLabelField]]));
918 }
919 } else {
920 if (!$out) {
921 $out = htmlspecialchars($prefixString . $val[$altLabelField]);
922 } else {
923 $out .= $splitString . htmlspecialchars(($prefixString . $val[$altLabelField]));
924 }
925 }
926 }
927 }
928 }
929 }
930 }
931 return $out;
932 }
933
934 /**
935 * Render table header
936 *
937 * @param array $row Table columns
938 * @param array $conf Table TCA
939 * @param string $table Table name
940 * @return string HTML of table header
941 */
942 public function resultRowTitles($row, $conf, $table) {
943 $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
944 $tableHeader = array();
945 // Start header row
946 $tableHeader[] = '<thead><tr>';
947 // Iterate over given columns
948 foreach ($row as $fieldName => $fieldValue) {
949 if (GeneralUtility::inList($SET['queryFields'], $fieldName) || !$SET['queryFields'] && $fieldName != 'pid' && $fieldName != 'deleted') {
950 if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels']) {
951 $title = $GLOBALS['LANG']->sL($conf['columns'][$fieldName]['label'] ? $conf['columns'][$fieldName]['label'] : $fieldName, TRUE);
952 } else {
953 $title = $GLOBALS['LANG']->sL($fieldName, TRUE);
954 }
955 $tableHeader[] = '<th>' . $title . '</th>';
956 }
957 }
958 // Add empty icon column
959 $tableHeader[] = '<th></th>';
960 // Close header row
961 $tableHeader[] = '</tr></thead>';
962 return implode(LF, $tableHeader);
963 }
964
965 /**
966 * CSV row titles
967 *
968 * @param array $row
969 * @param array $conf
970 * @param mixed $table Not used
971 * @return string
972 */
973 public function csvRowTitles($row, $conf, $table) {
974 $out = '';
975 $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
976 foreach ($row as $fieldName => $fieldValue) {
977 if (GeneralUtility::inList($SET['queryFields'], $fieldName) || !$SET['queryFields'] && $fieldName != 'pid') {
978 if (!$out) {
979 if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels']) {
980 $out = $GLOBALS['LANG']->sL($conf['columns'][$fieldName]['label'] ? $conf['columns'][$fieldName]['label'] : $fieldName, TRUE);
981 } else {
982 $out = $GLOBALS['LANG']->sL($fieldName, TRUE);
983 }
984 } else {
985 if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels']) {
986 $out .= ',' . $GLOBALS['LANG']->sL(($conf['columns'][$fieldName]['label'] ? $conf['columns'][$fieldName]['label'] : $fieldName), TRUE);
987 } else {
988 $out .= ',' . $GLOBALS['LANG']->sL($fieldName, TRUE);
989 }
990 }
991 }
992 }
993 return $out;
994 }
995
996 /**
997 * Sets the current name of the input form.
998 *
999 * @param string $formName The name of the form.
1000 * @return void
1001 */
1002 public function setFormName($formName) {
1003 $this->formName = trim($formName);
1004 }
1005
1006 }