TYPO3 CMS  TYPO3_8-7
QueryView.php
Go to the documentation of this file.
1 <?php
2 
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
33 
38 class QueryView
39 {
43  public $storeList = 'search_query_smallparts,search_result_labels,labels_noprefix,show_deleted,queryConfig,queryTable,queryFields,queryLimit,queryOrder,queryOrderDesc,queryOrder2,queryOrder2Desc,queryGroup,search_query_makeQuery';
44 
48  public $downloadScript = 'index.php';
49 
53  public $formW = 48;
54 
58  public $noDownloadB = 0;
59 
63  public $hookArray = [];
64 
68  protected $formName = '';
69 
73  protected $iconFactory;
74 
78  protected $tableArray = [];
79 
83  protected $languageService;
84 
89 
93  public function __construct()
94  {
95  $this->backendUserAuthentication = $GLOBALS['BE_USER'];
96  $this->languageService = $GLOBALS['LANG'];
97  $this->languageService->includeLLFile('EXT:lang/Resources/Private/Language/locallang_t3lib_fullsearch.xlf');
98  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
99  }
100 
106  public function form()
107  {
108  $markup = [];
109  $markup[] = '<div class="form-group">';
110  $markup[] = '<input placeholder="Search Word" class="form-control" type="search" name="SET[sword]" value="'
111  . htmlspecialchars($GLOBALS['SOBE']->MOD_SETTINGS['sword']) . '">';
112  $markup[] = '</div>';
113  $markup[] = '<div class="form-group">';
114  $markup[] = '<input class="btn btn-default" type="submit" name="submit" value="Search All Records">';
115  $markup[] = '</div>';
116  return implode(LF, $markup);
117  }
118 
124  public function makeStoreControl()
125  {
126  // Load/Save
127  $storeArray = $this->initStoreArray();
128 
129  $opt = [];
130  foreach ($storeArray as $k => $v) {
131  $opt[] = '<option value="' . htmlspecialchars($k) . '">' . htmlspecialchars($v) . '</option>';
132  }
133  // Actions:
134  if (ExtensionManagementUtility::isLoaded('sys_action') && $this->backendUserAuthentication->isAdmin()) {
135  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_action');
136  $queryBuilder->getRestrictions()->removeAll();
137  $statement = $queryBuilder->select('uid', 'title')
138  ->from('sys_action')
139  ->where($queryBuilder->expr()->eq('type', $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT)))
140  ->orderBy('title')
141  ->execute();
142  $opt[] = '<option value="0">__Save to Action:__</option>';
143  while ($row = $statement->fetch()) {
144  $opt[] = '<option value="-' . (int)$row['uid'] . '">' . htmlspecialchars(($row['title']
145  . ' [' . (int)$row['uid'] . ']')) . '</option>';
146  }
147  }
148  $markup = [];
149  $markup[] = '<div class="load-queries">';
150  $markup[] = ' <div class="form-inline">';
151  $markup[] = ' <div class="form-group">';
152  $markup[] = ' <select class="form-control" name="storeControl[STORE]" onChange="document.forms[0]'
153  . '[\'storeControl[title]\'].value= this.options[this.selectedIndex].value!=0 '
154  . '? this.options[this.selectedIndex].text : \'\';">' . implode(LF, $opt) . '</select>';
155  $markup[] = ' <input class="form-control" name="storeControl[title]" value="" type="text" max="80">';
156  $markup[] = ' <input class="btn btn-default" type="submit" name="storeControl[LOAD]" value="Load">';
157  $markup[] = ' <input class="btn btn-default" type="submit" name="storeControl[SAVE]" value="Save">';
158  $markup[] = ' <input class="btn btn-default" type="submit" name="storeControl[REMOVE]" value="Remove">';
159  $markup[] = ' </div>';
160  $markup[] = ' </div>';
161  $markup[] = '</div>';
162 
163  return implode(LF, $markup);
164  }
165 
171  public function initStoreArray()
172  {
173  $storeArray = [
174  '0' => '[New]'
175  ];
176  $savedStoreArray = unserialize($GLOBALS['SOBE']->MOD_SETTINGS['storeArray'], ['allowed_classes' => false]);
177  if (is_array($savedStoreArray)) {
178  $storeArray = array_merge($storeArray, $savedStoreArray);
179  }
180  return $storeArray;
181  }
182 
190  public function cleanStoreQueryConfigs($storeQueryConfigs, $storeArray)
191  {
192  if (is_array($storeQueryConfigs)) {
193  foreach ($storeQueryConfigs as $k => $v) {
194  if (!isset($storeArray[$k])) {
195  unset($storeQueryConfigs[$k]);
196  }
197  }
198  }
199  return $storeQueryConfigs;
200  }
201 
209  public function addToStoreQueryConfigs($storeQueryConfigs, $index)
210  {
211  $keyArr = explode(',', $this->storeList);
212  $storeQueryConfigs[$index] = [];
213  foreach ($keyArr as $k) {
214  $storeQueryConfigs[$index][$k] = $GLOBALS['SOBE']->MOD_SETTINGS[$k];
215  }
216  return $storeQueryConfigs;
217  }
218 
225  public function saveQueryInAction($uid)
226  {
227  if (ExtensionManagementUtility::isLoaded('sys_action')) {
228  $keyArr = explode(',', $this->storeList);
229  $saveArr = [];
230  foreach ($keyArr as $k) {
231  $saveArr[$k] = $GLOBALS['SOBE']->MOD_SETTINGS[$k];
232  }
233  // Show query
234  if ($saveArr['queryTable']) {
236  $queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
237  $queryGenerator->init('queryConfig', $saveArr['queryTable']);
238  $queryGenerator->makeSelectorTable($saveArr);
239  $queryGenerator->enablePrefix = 1;
240  $queryString = $queryGenerator->getQuery($queryGenerator->queryConfig);
241 
242  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
243  ->getQueryBuilderForTable($queryGenerator->table);
244  $queryBuilder->getRestrictions()->removeAll()
245  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
246  $rowCount = $queryBuilder->count('*')
247  ->from($queryGenerator->table)
248  ->where(QueryHelper::stripLogicalOperatorPrefix($queryString))
249  ->execute()->fetchColumn(0);
250 
251  $t2DataValue = [
252  'qC' => $saveArr,
253  'qCount' => $rowCount,
254  'qSelect' => $queryGenerator->getSelectQuery($queryString),
255  'qString' => $queryString
256  ];
257  GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('sys_action')
258  ->update(
259  'sys_action',
260  ['t2_data' => serialize($t2DataValue)],
261  ['uid' => (int)$uid],
262  ['t2_data' => Connection::PARAM_LOB]
263  );
264  }
265  return 1;
266  }
267  return null;
268  }
269 
278  public function loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray)
279  {
280  if ($storeQueryConfigs[$storeIndex]) {
281  $keyArr = explode(',', $this->storeList);
282  foreach ($keyArr as $k) {
283  $writeArray[$k] = $storeQueryConfigs[$storeIndex][$k];
284  }
285  }
286  return $writeArray;
287  }
288 
294  public function procesStoreControl()
295  {
296  $storeArray = $this->initStoreArray();
297  $storeQueryConfigs = unserialize($GLOBALS['SOBE']->MOD_SETTINGS['storeQueryConfigs'], ['allowed_classes' => false]);
298  $storeControl = GeneralUtility::_GP('storeControl');
299  $storeIndex = (int)$storeControl['STORE'];
300  $saveStoreArray = 0;
301  $writeArray = [];
302  $msg = '';
303  if (is_array($storeControl)) {
304  if ($storeControl['LOAD']) {
305  if ($storeIndex > 0) {
306  $writeArray = $this->loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray);
307  $saveStoreArray = 1;
308  $flashMessage = GeneralUtility::makeInstance(
309  FlashMessage::class,
310  sprintf($this->languageService->getLL('query_loaded'), $storeArray[$storeIndex])
311  );
312  } elseif ($storeIndex < 0 && ExtensionManagementUtility::isLoaded('sys_action')) {
313  $actionRecord = BackendUtility::getRecord('sys_action', abs($storeIndex));
314  if (is_array($actionRecord)) {
315  $dA = unserialize($actionRecord['t2_data'], ['allowed_classes' => false]);
316  $dbSC = [];
317  if (is_array($dA['qC'])) {
318  $dbSC[0] = $dA['qC'];
319  }
320  $writeArray = $this->loadStoreQueryConfigs($dbSC, '0', $writeArray);
321  $saveStoreArray = 1;
322  $flashMessage = GeneralUtility::makeInstance(
323  FlashMessage::class,
324  sprintf($this->languageService->getLL('query_from_action_loaded'), $actionRecord['title'])
325  );
326  }
327  }
328  } elseif ($storeControl['SAVE']) {
329  if ($storeIndex < 0) {
330  $qOK = $this->saveQueryInAction(abs($storeIndex));
331  if ($qOK) {
332  $flashMessage = GeneralUtility::makeInstance(
333  FlashMessage::class,
334  $this->languageService->getLL('query_saved')
335  );
336  } else {
337  $flashMessage = GeneralUtility::makeInstance(
338  FlashMessage::class,
339  $this->languageService->getLL('query_notsaved'),
340  '',
342  );
343  }
344  } else {
345  if (trim($storeControl['title'])) {
346  if ($storeIndex > 0) {
347  $storeArray[$storeIndex] = $storeControl['title'];
348  } else {
349  $storeArray[] = $storeControl['title'];
350  end($storeArray);
351  $storeIndex = key($storeArray);
352  }
353  $storeQueryConfigs = $this->addToStoreQueryConfigs($storeQueryConfigs, $storeIndex);
354  $saveStoreArray = 1;
355  $flashMessage = GeneralUtility::makeInstance(
356  FlashMessage::class,
357  $this->languageService->getLL('query_saved')
358  );
359  }
360  }
361  } elseif ($storeControl['REMOVE']) {
362  if ($storeIndex > 0) {
363  $flashMessage = GeneralUtility::makeInstance(
364  FlashMessage::class,
365  sprintf($this->languageService->getLL('query_removed'), $storeArray[$storeControl['STORE']])
366  );
367  // Removing
368  unset($storeArray[$storeControl['STORE']]);
369  $saveStoreArray = 1;
370  }
371  }
372  if (!empty($flashMessage)) {
373  $msg = GeneralUtility::makeInstance(FlashMessageRendererResolver::class)
374  ->resolve()
375  ->render([$flashMessage]);
376  }
377  }
378  if ($saveStoreArray) {
379  // Making sure, index 0 is not set!
380  unset($storeArray[0]);
381  $writeArray['storeArray'] = serialize($storeArray);
382  $writeArray['storeQueryConfigs'] =
383  serialize($this->cleanStoreQueryConfigs($storeQueryConfigs, $storeArray));
384  $GLOBALS['SOBE']->MOD_SETTINGS = BackendUtility::getModuleData(
385  $GLOBALS['SOBE']->MOD_MENU,
386  $writeArray,
387  $GLOBALS['SOBE']->MCONF['name'],
388  'ses'
389  );
390  }
391  return $msg;
392  }
393 
399  public function queryMaker()
400  {
401  $output = '';
402  if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3lib_fullsearch'])) {
403  $this->hookArray = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3lib_fullsearch'];
404  }
405  $msg = $this->procesStoreControl();
406  if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableStoreControl']) {
407  $output .= '<h2>Load/Save Query</h2>';
408  $output .= '<div>' . $this->makeStoreControl() . '</div>';
409  $output .= $msg;
410  }
411  // Query Maker:
412  $queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
413  $queryGenerator->init('queryConfig', $GLOBALS['SOBE']->MOD_SETTINGS['queryTable']);
414  if ($this->formName) {
415  $queryGenerator->setFormName($this->formName);
416  }
417  $tmpCode = $queryGenerator->makeSelectorTable($GLOBALS['SOBE']->MOD_SETTINGS);
418  $output .= '<div id="query"></div><h2>Make query</h2><div>' . $tmpCode . '</div>';
419  $mQ = $GLOBALS['SOBE']->MOD_SETTINGS['search_query_makeQuery'];
420  // Make form elements:
421  if ($queryGenerator->table && is_array($GLOBALS['TCA'][$queryGenerator->table])) {
422  if ($mQ) {
423  // Show query
424  $queryGenerator->enablePrefix = 1;
425  $queryString = $queryGenerator->getQuery($queryGenerator->queryConfig);
426  $selectQueryString = $queryGenerator->getSelectQuery($queryString);
427  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($queryGenerator->table);
428 
429  $isConnectionMysql = strpos($connection->getServerVersion(), 'MySQL') === 0;
430  $fullQueryString = '';
431  try {
432  if ($mQ === 'explain' && $isConnectionMysql) {
433  // EXPLAIN is no ANSI SQL, for now this is only executed on mysql
434  // @todo: Move away from getSelectQuery() or model differently
435  $fullQueryString = 'EXPLAIN ' . $selectQueryString;
436  $dataRows = $connection->executeQuery('EXPLAIN ' . $selectQueryString)->fetchAll();
437  } elseif ($mQ === 'count') {
438  $queryBuilder = $connection->createQueryBuilder();
439  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
440  $dataRows = $queryBuilder->count('*')
441  ->from($queryGenerator->table)
442  ->where(QueryHelper::stripLogicalOperatorPrefix($queryString));
443  $fullQueryString = $queryBuilder->getSQL();
444  $dataRows = [$queryBuilder->execute()->fetchColumn(0)];
445  } else {
446  $fullQueryString = $selectQueryString;
447  $dataRows = $connection->executeQuery($selectQueryString)->fetchAll();
448  }
449  if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableShowSQLQuery']) {
450  $output .= '<h2>SQL query</h2><div><pre>' . htmlspecialchars($fullQueryString) . '</pre></div>';
451  }
452  $cPR = $this->getQueryResultCode($mQ, $dataRows, $queryGenerator->table);
453  $output .= '<h2>' . $cPR['header'] . '</h2><div>' . $cPR['content'] . '</div>';
454  } catch (DBALException $e) {
455  if (!$this->backendUserAuthentication->userTS['mod.']['dbint.']['disableShowSQLQuery']) {
456  $output .= '<h2>SQL query</h2><div><pre>' . htmlspecialchars($fullQueryString) . '</pre></div>';
457  }
458  $out = '<p><strong>Error: <span class="text-danger">'
459  . $e->getMessage()
460  . '</span></strong></p>';
461  $output .= '<h2>SQL error</h2><div>' . $out . '</div>';
462  }
463  }
464  }
465  return '<div class="query-builder">' . $output . '</div>';
466  }
467 
477  public function getQueryResultCode($type, array $dataRows, $table)
478  {
479  $out = '';
480  $cPR = [];
481  switch ($type) {
482  case 'count':
483  $cPR['header'] = 'Count';
484  $cPR['content'] = '<BR><strong>' . (int)$dataRows[0] . '</strong> records selected.';
485  break;
486  case 'all':
487  $rowArr = [];
488  $dataRow = null;
489  foreach ($dataRows as $dataRow) {
490  $rowArr[] = $this->resultRowDisplay($dataRow, $GLOBALS['TCA'][$table], $table);
491  }
492  if (is_array($this->hookArray['beforeResultTable'])) {
493  foreach ($this->hookArray['beforeResultTable'] as $_funcRef) {
494  $out .= GeneralUtility::callUserFunction($_funcRef, $GLOBALS['SOBE']->MOD_SETTINGS, $this);
495  }
496  }
497  if (!empty($rowArr)) {
498  $cPR['header'] = 'Result';
499  $out .= '<table class="table table-striped table-hover">'
500  . $this->resultRowTitles($dataRow, $GLOBALS['TCA'][$table], $table) . implode(LF, $rowArr)
501  . '</table>';
502  } else {
504  }
505 
506  $cPR['content'] = $out;
507  break;
508  case 'csv':
509  $rowArr = [];
510  $first = 1;
511  foreach ($dataRows as $dataRow) {
512  if ($first) {
513  $rowArr[] = $this->csvValues(array_keys($dataRow), ',', '');
514  $first = 0;
515  }
516  $rowArr[] = $this->csvValues($dataRow, ',', '"', $GLOBALS['TCA'][$table], $table);
517  }
518  if (!empty($rowArr)) {
519  $cPR['header'] = 'Result';
520  $out .= '<textarea name="whatever" rows="20" class="text-monospace" style="width:100%">'
521  . htmlspecialchars(implode(LF, $rowArr))
522  . '</textarea>';
523  if (!$this->noDownloadB) {
524  $out .= '<br><input class="btn btn-default" type="submit" name="download_file" '
525  . 'value="Click to download file" onClick="window.location.href=' . htmlspecialchars(GeneralUtility::quoteJSvalue($this->downloadScript))
526  . ';">';
527  }
528  // Downloads file:
529  // @todo: args. routing anyone?
530  if (GeneralUtility::_GP('download_file')) {
531  $filename = 'TYPO3_' . $table . '_export_' . date('dmy-Hi') . '.csv';
532  $mimeType = 'application/octet-stream';
533  header('Content-Type: ' . $mimeType);
534  header('Content-Disposition: attachment; filename=' . $filename);
535  echo implode(CRLF, $rowArr);
536  die;
537  }
538  } else {
540  }
541  $cPR['content'] = $out;
542  break;
543  case 'explain':
544  default:
545  foreach ($dataRows as $dataRow) {
546  $out .= '<br />' . DebugUtility::viewArray($dataRow);
547  }
548  $cPR['header'] = 'Explain SQL query';
549  $cPR['content'] = $out;
550  }
551  return $cPR;
552  }
553 
564  public function csvValues($row, $delim = ',', $quote = '"', $conf = [], $table = '')
565  {
566  $valueArray = $row;
567  if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels'] && $table) {
568  foreach ($valueArray as $key => $val) {
569  $valueArray[$key] = $this->getProcessedValueExtra($table, $key, $val, $conf, ';');
570  }
571  }
572  return CsvUtility::csvValues($valueArray, $delim, $quote);
573  }
574 
582  public function tableWrap($str)
583  {
585  return '<pre>' . $str . '</pre>';
586  }
587 
593  public function search()
594  {
595  $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
596  $swords = $SET['sword'];
597  $out = '';
598  if ($swords) {
599  foreach ($GLOBALS['TCA'] as $table => $value) {
600  // Get fields list
601  $conf = $GLOBALS['TCA'][$table];
602  // Avoid querying tables with no columns
603  if (empty($conf['columns'])) {
604  continue;
605  }
606  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
607  $tableColumns = $connection->getSchemaManager()->listTableColumns($table);
608  $fieldsInDatabase = [];
609  foreach ($tableColumns as $column) {
610  $fieldsInDatabase[] = $column->getName();
611  }
612  $fields = array_intersect(array_keys($conf['columns']), $fieldsInDatabase);
613 
614  $queryBuilder = $connection->createQueryBuilder();
615  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
616  $queryBuilder->count('*')->from($table);
617  $likes = [];
618  $excapedLikeString = '%' . $queryBuilder->escapeLikeWildcards($swords) . '%';
619  foreach ($fields as $field) {
620  $likes[] = $queryBuilder->expr()->like(
621  $field,
622  $queryBuilder->createNamedParameter($excapedLikeString, \PDO::PARAM_STR)
623  );
624  }
625  $count = $queryBuilder->orWhere(...$likes)->execute()->fetchColumn(0);
626 
627  if ($count > 0) {
628  $queryBuilder = $connection->createQueryBuilder();
629  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
630  $queryBuilder->select('uid', $conf['ctrl']['label'])
631  ->from($table)
632  ->setMaxResults(200);
633  $likes = [];
634  foreach ($fields as $field) {
635  $likes[] = $queryBuilder->expr()->like(
636  $field,
637  $queryBuilder->createNamedParameter($excapedLikeString, \PDO::PARAM_STR)
638  );
639  }
640  $statement = $queryBuilder->orWhere(...$likes)->execute();
641  $lastRow = null;
642  $rowArr = [];
643  while ($row = $statement->fetch()) {
644  $rowArr[] = $this->resultRowDisplay($row, $conf, $table);
645  $lastRow = $row;
646  }
647  $markup = [];
648  $markup[] = '<div class="panel panel-default">';
649  $markup[] = ' <div class="panel-heading">';
650  $markup[] = htmlspecialchars($this->languageService->sL($conf['ctrl']['title'])) . ' (' . $count . ')';
651  $markup[] = ' </div>';
652  $markup[] = ' <table class="table table-striped table-hover">';
653  $markup[] = $this->resultRowTitles($lastRow, $conf, $table);
654  $markup[] = implode(LF, $rowArr);
655  $markup[] = ' </table>';
656  $markup[] = '</div>';
657 
658  $out .= implode(LF, $markup);
659  }
660  }
661  }
662  return $out;
663  }
664 
673  public function resultRowDisplay($row, $conf, $table)
674  {
675  $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
676  $out = '<tr>';
677  foreach ($row as $fieldName => $fieldValue) {
678  if (GeneralUtility::inList($SET['queryFields'], $fieldName)
679  || !$SET['queryFields']
680  && $fieldName !== 'pid'
681  && $fieldName !== 'deleted'
682  ) {
683  if ($SET['search_result_labels']) {
684  $fVnew = $this->getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, '<br />');
685  } else {
686  $fVnew = htmlspecialchars($fieldValue);
687  }
688  $out .= '<td>' . $fVnew . '</td>';
689  }
690  }
691  $out .= '<td>';
692  if (!$row['deleted']) {
693  $out .= '<div class="btn-group" role="group">';
694  $url = BackendUtility::getModuleUrl('record_edit', [
695  'edit' => [
696  $table => [
697  $row['uid'] => 'edit'
698  ]
699  ],
700  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
702  ]);
703  $out .= '<a class="btn btn-default" href="' . htmlspecialchars($url) . '">'
704  . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>';
705  $out .= '</div><div class="btn-group" role="group">';
706  $out .= '<a class="btn btn-default" href="#" onClick="top.launchView(\'' . $table . '\',' . $row['uid']
707  . ');return false;">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render()
708  . '</a>';
709  $out .= '</div>';
710  } else {
711  $out .= '<div class="btn-group" role="group">';
712  $out .= '<a class="btn btn-default" href="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_db', [
713  'cmd' => [
714  $table => [
715  $row['uid'] => [
716  'undelete' => 1
717  ]
718  ]
719  ],
720  'redirect' => GeneralUtility::linkThisScript()
721  ])) . '" title="' . htmlspecialchars($this->languageService->getLL('undelete_only')) . '">';
722  $out .= $this->iconFactory->getIcon('actions-edit-restore', Icon::SIZE_SMALL)->render() . '</a>';
723  $formEngineParameters = [
724  'edit' => [
725  $table => [
726  $row['uid'] => 'edit'
727  ]
728  ],
729  'returnUrl' => GeneralUtility::linkThisScript()
730  ];
731  $redirectUrl = BackendUtility::getModuleUrl('record_edit', $formEngineParameters);
732  $out .= '<a class="btn btn-default" href="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_db', [
733  'cmd' => [
734  $table => [
735  $row['uid'] => [
736  'undelete' => 1
737  ]
738  ]
739  ],
740  'redirect' => $redirectUrl
741  ])) . '" title="' . htmlspecialchars($this->languageService->getLL('undelete_and_edit')) . '">';
742  $out .= $this->iconFactory->getIcon('actions-edit-restore-edit', Icon::SIZE_SMALL)->render() . '</a>';
743  $out .= '</div>';
744  }
745  $_params = [$table => $row];
746  if (is_array($this->hookArray['additionalButtons'])) {
747  foreach ($this->hookArray['additionalButtons'] as $_funcRef) {
748  $out .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
749  }
750  }
751  $out .= '</td></tr>';
752  return $out;
753  }
754 
765  public function getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, $splitString)
766  {
767  $out = '';
768  $fields = [];
769  // Analysing the fields in the table.
770  if (is_array($GLOBALS['TCA'][$table])) {
771  $fC = $GLOBALS['TCA'][$table]['columns'][$fieldName];
772  $fields = $fC['config'];
773  $fields['exclude'] = $fC['exclude'];
774  if (is_array($fC) && $fC['label']) {
775  $fields['label'] = preg_replace('/:$/', '', trim($this->languageService->sL($fC['label'])));
776  switch ($fields['type']) {
777  case 'input':
778  if (preg_match('/int|year/i', $fields['eval'])) {
779  $fields['type'] = 'number';
780  } elseif (preg_match('/time/i', $fields['eval'])) {
781  $fields['type'] = 'time';
782  } elseif (preg_match('/date/i', $fields['eval'])) {
783  $fields['type'] = 'date';
784  } else {
785  $fields['type'] = 'text';
786  }
787  break;
788  case 'check':
789  if (!$fields['items']) {
790  $fields['type'] = 'boolean';
791  } else {
792  $fields['type'] = 'binary';
793  }
794  break;
795  case 'radio':
796  $fields['type'] = 'multiple';
797  break;
798  case 'select':
799  $fields['type'] = 'multiple';
800  if ($fields['foreign_table']) {
801  $fields['type'] = 'relation';
802  }
803  if ($fields['special']) {
804  $fields['type'] = 'text';
805  }
806  break;
807  case 'group':
808  $fields['type'] = 'files';
809  if ($fields['internal_type'] === 'db') {
810  $fields['type'] = 'relation';
811  }
812  break;
813  case 'user':
814  case 'flex':
815  case 'passthrough':
816  case 'none':
817  case 'text':
818  default:
819  $fields['type'] = 'text';
820  }
821  } else {
822  $fields['label'] = '[FIELD: ' . $fieldName . ']';
823  switch ($fieldName) {
824  case 'pid':
825  $fields['type'] = 'relation';
826  $fields['allowed'] = 'pages';
827  break;
828  case 'cruser_id':
829  $fields['type'] = 'relation';
830  $fields['allowed'] = 'be_users';
831  break;
832  case 'tstamp':
833  case 'crdate':
834  $fields['type'] = 'time';
835  break;
836  default:
837  $fields['type'] = 'number';
838  }
839  }
840  }
841  switch ($fields['type']) {
842  case 'date':
843  if ($fieldValue != -1) {
844  $out = strftime('%d-%m-%Y', $fieldValue);
845  }
846  break;
847  case 'time':
848  if ($fieldValue != -1) {
849  if ($splitString === '<br />') {
850  $out = strftime('%H:%M' . $splitString . '%d-%m-%Y', $fieldValue);
851  } else {
852  $out = strftime('%H:%M %d-%m-%Y', $fieldValue);
853  }
854  }
855  break;
856  case 'multiple':
857  case 'binary':
858  case 'relation':
859  $out = $this->makeValueList($fieldName, $fieldValue, $fields, $table, $splitString);
860  break;
861  case 'boolean':
862  $out = $fieldValue ? 'True' : 'False';
863  break;
864  case 'files':
865  default:
866  $out = htmlspecialchars($fieldValue);
867  }
868  return $out;
869  }
870 
881  public function getTreeList($id, $depth, $begin = 0, $permsClause = null)
882  {
883  $depth = (int)$depth;
884  $begin = (int)$begin;
885  $id = (int)$id;
886  if ($id < 0) {
887  $id = abs($id);
888  }
889  if ($begin == 0) {
890  $theList = $id;
891  } else {
892  $theList = '';
893  }
894  if ($id && $depth > 0) {
895  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
896  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
897  $statement = $queryBuilder->select('uid')
898  ->from('pages')
899  ->where(
900  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)),
901  QueryHelper::stripLogicalOperatorPrefix($permsClause)
902  )
903  ->execute();
904  while ($row = $statement->fetch()) {
905  if ($begin <= 0) {
906  $theList .= ',' . $row['uid'];
907  }
908  if ($depth > 1) {
909  $theList .= $this->getTreeList($row['uid'], $depth - 1, $begin - 1, $permsClause);
910  }
911  }
912  }
913  return $theList;
914  }
915 
926  public function makeValueList($fieldName, $fieldValue, $conf, $table, $splitString)
927  {
928  $fieldSetup = $conf;
929  $out = '';
930  if ($fieldSetup['type'] === 'files') {
931  $d = dir(PATH_site . $fieldSetup['uploadfolder']);
932  while (false !== ($entry = $d->read())) {
933  if ($entry === '.' || $entry === '..') {
934  continue;
935  }
936  $fileArray[] = $entry;
937  }
938  $d->close();
939  natcasesort($fileArray);
940  foreach ($fileArray as $fileName) {
941  if (GeneralUtility::inList($fieldValue, $fileName) || $fieldValue == $fileName) {
942  if ($out !== '') {
943  $out .= $splitString;
944  }
945  $out .= htmlspecialchars($fileName);
946  }
947  }
948  }
949  if ($fieldSetup['type'] === 'multiple') {
950  foreach ($fieldSetup['items'] as $key => $val) {
951  if (substr($val[0], 0, 4) === 'LLL:') {
952  $value = $this->languageService->sL($val[0]);
953  } else {
954  $value = $val[0];
955  }
956  if (GeneralUtility::inList($fieldValue, $val[1]) || $fieldValue == $val[1]) {
957  if ($out !== '') {
958  $out .= $splitString;
959  }
960  $out .= htmlspecialchars($value);
961  }
962  }
963  }
964  if ($fieldSetup['type'] === 'binary') {
965  foreach ($fieldSetup['items'] as $Key => $val) {
966  if (substr($val[0], 0, 4) === 'LLL:') {
967  $value = $this->languageService->sL($val[0]);
968  } else {
969  $value = $val[0];
970  }
971  if ($out !== '') {
972  $out .= $splitString;
973  }
974  $out .= htmlspecialchars($value);
975  }
976  }
977  if ($fieldSetup['type'] === 'relation') {
978  $dontPrefixFirstTable = 0;
979  $useTablePrefix = 0;
980  if ($fieldSetup['items']) {
981  foreach ($fieldSetup['items'] as $key => $val) {
982  if (substr($val[0], 0, 4) === 'LLL:') {
983  $value = $this->languageService->sL($val[0]);
984  } else {
985  $value = $val[0];
986  }
987  if (GeneralUtility::inList($fieldValue, $value) || $fieldValue == $value) {
988  if ($out !== '') {
989  $out .= $splitString;
990  }
991  $out .= htmlspecialchars($value);
992  }
993  }
994  }
995  if (stristr($fieldSetup['allowed'], ',')) {
996  $from_table_Arr = explode(',', $fieldSetup['allowed']);
997  $useTablePrefix = 1;
998  if (!$fieldSetup['prepend_tname']) {
999  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1000  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1001  $statement = $queryBuilder->select($fieldName)->from($table)->execute();
1002  while ($row = $statement->fetch()) {
1003  if (stristr($row[$fieldName], ',')) {
1004  $checkContent = explode(',', $row[$fieldName]);
1005  foreach ($checkContent as $singleValue) {
1006  if (!stristr($singleValue, '_')) {
1007  $dontPrefixFirstTable = 1;
1008  }
1009  }
1010  } else {
1011  $singleValue = $row[$fieldName];
1012  if ($singleValue !== '' && !stristr($singleValue, '_')) {
1013  $dontPrefixFirstTable = 1;
1014  }
1015  }
1016  }
1017  }
1018  } else {
1019  $from_table_Arr[0] = $fieldSetup['allowed'];
1020  }
1021  if ($fieldSetup['prepend_tname']) {
1022  $useTablePrefix = 1;
1023  }
1024  if ($fieldSetup['foreign_table']) {
1025  $from_table_Arr[0] = $fieldSetup['foreign_table'];
1026  }
1027  $counter = 0;
1028  $useSelectLabels = 0;
1029  $useAltSelectLabels = 0;
1030  $tablePrefix = '';
1031  $labelFieldSelect = [];
1032  foreach ($from_table_Arr as $from_table) {
1033  if ($useTablePrefix && !$dontPrefixFirstTable && $counter != 1 || $counter == 1) {
1034  $tablePrefix = $from_table . '_';
1035  }
1036  $counter = 1;
1037  if (is_array($GLOBALS['TCA'][$from_table])) {
1038  $labelField = $GLOBALS['TCA'][$from_table]['ctrl']['label'];
1039  $altLabelField = $GLOBALS['TCA'][$from_table]['ctrl']['label_alt'];
1040  if ($GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items']) {
1041  $items = $GLOBALS['TCA'][$from_table]['columns'][$labelField]['config']['items'];
1042  foreach ($items as $labelArray) {
1043  if (substr($labelArray[0], 0, 4) === 'LLL:') {
1044  $labelFieldSelect[$labelArray[1]] = $this->languageService->sL($labelArray[0]);
1045  } else {
1046  $labelFieldSelect[$labelArray[1]] = $labelArray[0];
1047  }
1048  }
1049  $useSelectLabels = 1;
1050  }
1051  $altLabelFieldSelect = [];
1052  if ($GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items']) {
1053  $items = $GLOBALS['TCA'][$from_table]['columns'][$altLabelField]['config']['items'];
1054  foreach ($items as $altLabelArray) {
1055  if (substr($altLabelArray[0], 0, 4) === 'LLL:') {
1056  $altLabelFieldSelect[$altLabelArray[1]] = $this->languageService->sL($altLabelArray[0]);
1057  } else {
1058  $altLabelFieldSelect[$altLabelArray[1]] = $altLabelArray[0];
1059  }
1060  }
1061  $useAltSelectLabels = 1;
1062  }
1063 
1064  if (!$this->tableArray[$from_table]) {
1065  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($from_table);
1066  $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1067  $selectFields = ['uid', $labelField];
1068  if ($altLabelField) {
1069  $selectFields[] = $altLabelField;
1070  }
1071  $queryBuilder->select(...$selectFields)
1072  ->from($from_table)
1073  ->orderBy('uid');
1074  if (!$this->backendUserAuthentication->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts']) {
1075  $webMounts = $this->backendUserAuthentication->returnWebmounts();
1076  $perms_clause = $this->backendUserAuthentication->getPagePermsClause(1);
1077  $webMountPageTree = '';
1078  $webMountPageTreePrefix = '';
1079  foreach ($webMounts as $webMount) {
1080  if ($webMountPageTree) {
1081  $webMountPageTreePrefix = ',';
1082  }
1083  $webMountPageTree .= $webMountPageTreePrefix
1084  . $this->getTreeList($webMount, 999, ($begin = 0), $perms_clause);
1085  }
1086  if ($from_table === 'pages') {
1087  $queryBuilder->where(
1088  QueryHelper::stripLogicalOperatorPrefix($perms_clause),
1089  $queryBuilder->expr()->in(
1090  'uid',
1091  $queryBuilder->createNamedParameter(
1092  GeneralUtility::intExplode(',', $webMountPageTree),
1093  Connection::PARAM_INT_ARRAY
1094  )
1095  )
1096  );
1097  } else {
1098  $queryBuilder->where(
1099  $queryBuilder->expr()->in(
1100  'pid',
1101  $queryBuilder->createNamedParameter(
1102  GeneralUtility::intExplode(',', $webMountPageTree),
1103  Connection::PARAM_INT_ARRAY
1104  )
1105  )
1106  );
1107  }
1108  }
1109  $statement = $queryBuilder->execute();
1110  $this->tableArray[$from_table] = [];
1111  while ($row = $statement->fetch()) {
1112  $this->tableArray[$from_table][] = $row;
1113  }
1114  }
1115 
1116  foreach ($this->tableArray[$from_table] as $key => $val) {
1117  $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] =
1118  $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] == 1
1119  ? 'on'
1120  : $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'];
1121  $prefixString =
1122  $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] === 'on'
1123  ? ''
1124  : ' [' . $tablePrefix . $val['uid'] . '] ';
1125  if ($out !== '') {
1126  $out .= $splitString;
1127  }
1128  if (GeneralUtility::inList($fieldValue, $tablePrefix . $val['uid'])
1129  || $fieldValue == $tablePrefix . $val['uid']) {
1130  if ($useSelectLabels) {
1131  $out .= htmlspecialchars($prefixString . $labelFieldSelect[$val[$labelField]]);
1132  } elseif ($val[$labelField]) {
1133  $out .= htmlspecialchars($prefixString . $val[$labelField]);
1134  } elseif ($useAltSelectLabels) {
1135  $out .= htmlspecialchars($prefixString . $altLabelFieldSelect[$val[$altLabelField]]);
1136  } else {
1137  $out .= htmlspecialchars($prefixString . $val[$altLabelField]);
1138  }
1139  }
1140  }
1141  }
1142  }
1143  }
1144  return $out;
1145  }
1146 
1155  public function resultRowTitles($row, $conf, $table)
1156  {
1157  $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
1158  $tableHeader = [];
1159  // Start header row
1160  $tableHeader[] = '<thead><tr>';
1161  // Iterate over given columns
1162  foreach ($row as $fieldName => $fieldValue) {
1163  if (GeneralUtility::inList($SET['queryFields'], $fieldName)
1164  || !$SET['queryFields']
1165  && $fieldName !== 'pid'
1166  && $fieldName !== 'deleted'
1167  ) {
1168  if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels']) {
1169  $title = $this->languageService->sL($conf['columns'][$fieldName]['label']
1170  ? $conf['columns'][$fieldName]['label']
1171  : $fieldName);
1172  } else {
1173  $title = $this->languageService->sL($fieldName);
1174  }
1175  $tableHeader[] = '<th>' . htmlspecialchars($title) . '</th>';
1176  }
1177  }
1178  // Add empty icon column
1179  $tableHeader[] = '<th></th>';
1180  // Close header row
1181  $tableHeader[] = '</tr></thead>';
1182  return implode(LF, $tableHeader);
1183  }
1184 
1193  public function csvRowTitles($row, $conf, $table)
1194  {
1195  $out = '';
1196  $SET = $GLOBALS['SOBE']->MOD_SETTINGS;
1197  foreach ($row as $fieldName => $fieldValue) {
1198  if (GeneralUtility::inList($SET['queryFields'], $fieldName) || !$SET['queryFields'] && $fieldName !== 'pid') {
1199  if ($out !== '') {
1200  $out .= ',';
1201  }
1202  if ($GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels']) {
1203  $out = htmlspecialchars(
1204  $this->languageService->sL(
1205  $conf['columns'][$fieldName]['label'] ? $conf['columns'][$fieldName]['label'] : $fieldName
1206  )
1207  );
1208  } else {
1209  $out .= htmlspecialchars($this->languageService->sL($fieldName));
1210  }
1211  }
1212  }
1213  return $out;
1214  }
1215 
1221  public function setFormName($formName)
1222  {
1223  $this->formName = trim($formName);
1224  }
1225 
1230  private function renderNoResultsFoundMessage()
1231  {
1232  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, 'No rows selected!', '', FlashMessage::INFO);
1233  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1234  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1235  $defaultFlashMessageQueue->enqueue($flashMessage);
1236  }
1237 }
static csvValues(array $row, $delim=',', $quote='"')
Definition: CsvUtility.php:79
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static getModuleData( $MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
loadStoreQueryConfigs($storeQueryConfigs, $storeIndex, $writeArray)
Definition: QueryView.php:278
getQueryResultCode($type, array $dataRows, $table)
Definition: QueryView.php:477
static makeInstance($className,... $constructorArguments)
$fields
Definition: pages.php:4
resultRowTitles($row, $conf, $table)
Definition: QueryView.php:1155
getProcessedValueExtra($table, $fieldName, $fieldValue, $conf, $splitString)
Definition: QueryView.php:765
csvValues($row, $delim=',', $quote='"', $conf = [], $table = '')
Definition: QueryView.php:564
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
resultRowDisplay($row, $conf, $table)
Definition: QueryView.php:673
static stripLogicalOperatorPrefix(string $constraint)
addToStoreQueryConfigs($storeQueryConfigs, $index)
Definition: QueryView.php:209
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
cleanStoreQueryConfigs($storeQueryConfigs, $storeArray)
Definition: QueryView.php:190