TYPO3  7.6
DatabaseIntegrityView.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Lowlevel\View;
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 
30 
35 {
39  protected $formName = 'queryform';
40 
46  protected $moduleName = 'system_dbint';
47 
51  protected $view;
52 
56  protected $templatePath = 'EXT:lowlevel/Resources/Private/Templates/Backend/';
57 
61  protected $iconFactory;
62 
68  protected $moduleTemplate;
69 
73  public function __construct()
74  {
75  $this->getLanguageService()->includeLLFile('EXT:lowlevel/Resources/Private/Language/locallang.xlf');
76  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
77  $this->view = GeneralUtility::makeInstance(StandaloneView::class);
78  $this->view->getRequest()->setControllerExtensionName('lowlevel');
79  }
80 
86  public function init()
87  {
88  $this->MCONF['name'] = $this->moduleName;
89  $this->menuConfig();
90  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
91  $this->moduleTemplate->addJavaScriptCode(
92  'jumpToUrl',
93  '
94  function jumpToUrl(URL) {
95  window.location.href = URL;
96  return false;
97  }
98  '
99  );
100  }
101 
107  public function menuConfig()
108  {
109  $lang = $this->getLanguageService();
110  // MENU-ITEMS:
111  // If array, then it's a selector box menu
112  // If empty string it's just a variable, that'll be saved.
113  // Values NOT in this array will not be saved in the settings-array for the module.
114  $this->MOD_MENU = array(
115  'function' => array(
116  0 => $lang->getLL('menuTitle', true),
117  'records' => $lang->getLL('recordStatistics', true),
118  'relations' => $lang->getLL('databaseRelations', true),
119  'search' => $lang->getLL('fullSearch', true),
120  'refindex' => $lang->getLL('manageRefIndex', true)
121  ),
122  'search' => array(
123  'raw' => $lang->getLL('rawSearch', true),
124  'query' => $lang->getLL('advancedQuery', true)
125  ),
126  'search_query_smallparts' => '',
127  'search_result_labels' => '',
128  'labels_noprefix' => '',
129  'options_sortlabel' => '',
130  'show_deleted' => '',
131  'queryConfig' => '',
132  // Current query
133  'queryTable' => '',
134  // Current table
135  'queryFields' => '',
136  // Current tableFields
137  'queryLimit' => '',
138  // Current limit
139  'queryOrder' => '',
140  // Current Order field
141  'queryOrderDesc' => '',
142  // Current Order field descending flag
143  'queryOrder2' => '',
144  // Current Order2 field
145  'queryOrder2Desc' => '',
146  // Current Order2 field descending flag
147  'queryGroup' => '',
148  // Current Group field
149  'storeArray' => '',
150  // Used to store the available Query config memory banks
151  'storeQueryConfigs' => '',
152  // Used to store the available Query configs in memory
153  'search_query_makeQuery' => array(
154  'all' => $lang->getLL('selectRecords', true),
155  'count' => $lang->getLL('countResults', true),
156  'explain' => $lang->getLL('explainQuery', true),
157  'csv' => $lang->getLL('csvExport', true)
158  ),
159  'sword' => ''
160  );
161  // CLEAN SETTINGS
162  $OLD_MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, '', $this->moduleName, 'ses');
163  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName, 'ses');
164  if (GeneralUtility::_GP('queryConfig')) {
165  $qA = GeneralUtility::_GP('queryConfig');
166  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, array('queryConfig' => serialize($qA)), $this->moduleName, 'ses');
167  }
168  $addConditionCheck = GeneralUtility::_GP('qG_ins');
169  $setLimitToStart = false;
170  foreach ($OLD_MOD_SETTINGS as $key => $val) {
171  if (substr($key, 0, 5) == 'query' && $this->MOD_SETTINGS[$key] != $val && $key != 'queryLimit' && $key != 'use_listview') {
172  $setLimitToStart = true;
173  if ($key == 'queryTable' && !$addConditionCheck) {
174  $this->MOD_SETTINGS['queryConfig'] = '';
175  }
176  }
177  if ($key == 'queryTable' && $this->MOD_SETTINGS[$key] != $val) {
178  $this->MOD_SETTINGS['queryFields'] = '';
179  }
180  }
181  if ($setLimitToStart) {
182  $currentLimit = explode(',', $this->MOD_SETTINGS['queryLimit']);
183  if ($currentLimit[1]) {
184  $this->MOD_SETTINGS['queryLimit'] = '0,' . $currentLimit[1];
185  } else {
186  $this->MOD_SETTINGS['queryLimit'] = '0';
187  }
188  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $this->MOD_SETTINGS, $this->moduleName, 'ses');
189  }
190  }
191 
197  public function main()
198  {
199  switch ($this->MOD_SETTINGS['function']) {
200  case 'search':
201  $templateFilename = 'CustomSearch.html';
202  $this->func_search();
203  break;
204  case 'records':
205  $templateFilename = 'RecordStatistics.html';
206  $this->func_records();
207  break;
208  case 'relations':
209  $templateFilename = 'Relations.html';
210  $this->func_relations();
211  break;
212  case 'refindex':
213  $templateFilename = 'ReferenceIndex.html';
214  $this->func_refindex();
215  break;
216  default:
217  $templateFilename = 'IntegrityOverview.html';
218  $this->func_default();
219  }
220  $this->view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePath . $templateFilename));
221  $this->content = '<form action="" method="post" id="DatabaseIntegrityView" name="' . $this->formName . '">';
222  $this->content .= $this->view->render();
223  $this->content .= '</form>';
224 
225  // Setting up the shortcut button for docheader
226  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
227  // Shortcut
228  $shortCutButton = $buttonBar->makeShortcutButton()
229  ->setModuleName($this->moduleName)
230  ->setDisplayName($this->MOD_MENU['function'][$this->MOD_SETTINGS['function']])
231  ->setSetVariables(['function','search','search_query_makeQuery']);
232  $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT, 2);
233 
234  $this->getModuleMenu();
235  }
236 
243  public function printContent()
244  {
246  echo $this->content;
247  }
248 
258  {
259  $GLOBALS['SOBE'] = $this;
260  $this->init();
261  $this->main();
262 
263  $this->moduleTemplate->setContent($this->content);
264  $response->getBody()->write($this->moduleTemplate->renderContent());
265  return $response;
266  }
267 
271  protected function getModuleMenu()
272  {
273  $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
274  $menu->setIdentifier('DatabaseJumpMenu');
275 
276  foreach ($this->MOD_MENU['function'] as $controller => $title) {
277  $item = $menu
278  ->makeMenuItem()
279  ->setHref(
280  BackendUtility::getModuleUrl(
281  $this->moduleName,
282  [
283  'id' => $this->id,
284  'SET' => [
285  'function' => $controller
286  ]
287  ]
288  )
289  )
290  ->setTitle($title);
291  if ($controller === $this->MOD_SETTINGS['function']) {
292  $item->setActive(true);
293  }
294  $menu->addMenuItem($item);
295  }
296  $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
297  }
298 
304  protected function func_default()
305  {
306  $modules = array();
307  $availableModFuncs = array('records', 'relations', 'search', 'refindex');
308  foreach ($availableModFuncs as $modFunc) {
309  $modules[$modFunc] = BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=' . $modFunc;
310  }
311  $this->view->assign('availableFunctions', $modules);
312  }
313 
314  /****************************
315  *
316  * Functionality implementation
317  *
318  ****************************/
324  public function func_refindex()
325  {
326  $this->view->assign('PATH_typo3', PATH_typo3);
327 
328  if (GeneralUtility::_GP('_update') || GeneralUtility::_GP('_check')) {
329  $testOnly = (bool)GeneralUtility::_GP('_check');
330  // Call the functionality
331  $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
332  list(, $bodyContent) = $refIndexObj->updateIndex($testOnly);
333  $this->view->assign('content', str_replace('##LF##', '<br />', $bodyContent));
334  }
335  }
336 
342  public function func_search()
343  {
344  $lang = $this->getLanguageService();
345  $searchMode = $this->MOD_SETTINGS['search'];
346  $fullsearch = GeneralUtility::makeInstance(QueryView::class);
347  $fullsearch->setFormName($this->formName);
348  $submenu = '<div class="form-inline form-inline-spaced">';
349  $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search]', $searchMode, $this->MOD_MENU['search']);
350  if ($this->MOD_SETTINGS['search'] == 'query') {
351  $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search_query_makeQuery]', $this->MOD_SETTINGS['search_query_makeQuery'], $this->MOD_MENU['search_query_makeQuery']) . '<br />';
352  }
353  $submenu .= '</div>';
354  if ($this->MOD_SETTINGS['search'] == 'query') {
355  $submenu .= '<div class="checkbox"><label for="checkSearch_query_smallparts">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[search_query_smallparts]', $this->MOD_SETTINGS['search_query_smallparts'], '', '', 'id="checkSearch_query_smallparts"') . $lang->getLL('showSQL') . '</label></div>';
356  $submenu .= '<div class="checkbox"><label for="checkSearch_result_labels">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[search_result_labels]', $this->MOD_SETTINGS['search_result_labels'], '', '', 'id="checkSearch_result_labels"') . $lang->getLL('useFormattedStrings') . '</label></div>';
357  $submenu .= '<div class="checkbox"><label for="checkLabels_noprefix">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[labels_noprefix]', $this->MOD_SETTINGS['labels_noprefix'], '', '', 'id="checkLabels_noprefix"') . $lang->getLL('dontUseOrigValues') . '</label></div>';
358  $submenu .= '<div class="checkbox"><label for="checkOptions_sortlabel">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[options_sortlabel]', $this->MOD_SETTINGS['options_sortlabel'], '', '', 'id="checkOptions_sortlabel"') . $lang->getLL('sortOptions') . '</label></div>';
359  $submenu .= '<div class="checkbox"><label for="checkShow_deleted">' . BackendUtility::getFuncCheck($GLOBALS['SOBE']->id, 'SET[show_deleted]', $this->MOD_SETTINGS['show_deleted'], '', '', 'id="checkShow_deleted"') . $lang->getLL('showDeleted') . '</label></div>';
360  }
361  $this->view->assign('submenu', $submenu);
362  $this->view->assign('searchMode', $searchMode);
363  switch ($searchMode) {
364  case 'query':
365  $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Core/QueryGenerator');
366  $this->view->assign('queryMaker', $fullsearch->queryMaker());
367  break;
368  case 'raw':
369  default:
370  $this->view->assign('searchOptions', $fullsearch->form());
371  $this->view->assign('results', $fullsearch->search());
372  }
373  }
374 
380  public function func_records()
381  {
383  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
384  $admin->genTree(0);
385 
386  // Pages stat
387  $pageStatistic = array(
388  'total_pages' => array(
389  'icon' => $this->iconFactory->getIconForRecord('pages', array(), Icon::SIZE_SMALL)->render(),
390  'count' => count($admin->page_idArray)
391  ),
392  'hidden_pages' => array(
393  'icon' => $this->iconFactory->getIconForRecord('pages', array('hidden' => 1), Icon::SIZE_SMALL)->render(),
394  'count' => $admin->recStats['hidden']
395  ),
396  'deleted_pages' => array(
397  'icon' => $this->iconFactory->getIconForRecord('pages', array('deleted' => 1), Icon::SIZE_SMALL)->render(),
398  'count' => count($admin->recStats['deleted']['pages'])
399  )
400  );
401 
402  $lang = $this->getLanguageService();
403 
404  // Doktype
405  $doktypes = array();
406  $doktype = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
407  if (is_array($doktype)) {
408  foreach ($doktype as $setup) {
409  if ($setup[1] != '--div--') {
410  $doktypes[] = array(
411  'icon' => $this->iconFactory->getIconForRecord('pages', array('doktype' => $setup[1]), Icon::SIZE_SMALL)->render(),
412  'title' => $lang->sL($setup[0]) . ' (' . $setup[1] . ')',
413  'count' => (int)$admin->recStats['doktype'][$setup[1]]
414  );
415  }
416  }
417  }
418 
419  // Tables and lost records
420  $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
421  $id_list = rtrim($id_list, ',');
422  $admin->lostRecords($id_list);
423  if ($admin->fixLostRecord(GeneralUtility::_GET('fixLostRecords_table'), GeneralUtility::_GET('fixLostRecords_uid'))) {
424  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
425  $admin->genTree(0);
426  $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
427  $id_list = rtrim($id_list, ',');
428  $admin->lostRecords($id_list);
429  }
430  $tableStatistic = array();
431  $countArr = $admin->countRecords($id_list);
432  if (is_array($GLOBALS['TCA'])) {
433  foreach ($GLOBALS['TCA'] as $t => $value) {
434  if ($GLOBALS['TCA'][$t]['ctrl']['hideTable']) {
435  continue;
436  }
437  if ($t === 'pages' && $admin->lostPagesList !== '') {
438  $lostRecordCount = count(explode(',', $admin->lostPagesList));
439  } else {
440  $lostRecordCount = count($admin->lRecords[$t]);
441  }
442  if ($countArr['all'][$t]) {
443  $theNumberOfRe = (int)$countArr['non_deleted'][$t] . '/' . $lostRecordCount;
444  } else {
445  $theNumberOfRe = '';
446  }
447  $lr = '';
448  if (is_array($admin->lRecords[$t])) {
449  foreach ($admin->lRecords[$t] as $data) {
450  if (!GeneralUtility::inList($admin->lostPagesList, $data['pid'])) {
451  $lr .= '<div class="record"><a href="' . htmlspecialchars((BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=records&fixLostRecords_table=' . $t . '&fixLostRecords_uid=' . $data['uid'])) . '" title="' . $lang->getLL('fixLostRecord', true) . '">' . $this->iconFactory->getIcon('status-dialog-error', Icon::SIZE_SMALL)->render() . '</a>uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
452  } else {
453  $lr .= '<div class="record-noicon">uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
454  }
455  }
456  }
457  $tableStatistic[$t] = array(
458  'icon' => $this->iconFactory->getIconForRecord($t, array(), Icon::SIZE_SMALL)->render(),
459  'title' => $lang->sL($GLOBALS['TCA'][$t]['ctrl']['title']),
460  'count' => $theNumberOfRe,
461  'lostRecords' => $lr
462  );
463  }
464  }
465 
466  $this->view->assignMultiple(array(
467  'pages' => $pageStatistic,
468  'doktypes' => $doktypes,
469  'tables' => $tableStatistic
470  ));
471  }
472 
478  public function func_relations()
479  {
480  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
481  $fkey_arrays = $admin->getGroupFields('');
482  $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays);
483  $fileTest = $admin->testFileRefs();
484 
485  if (is_array($fileTest['noFile'])) {
486  ksort($fileTest['noFile']);
487  }
488  $this->view->assignMultiple(array(
489  'files' => $fileTest,
490  'select_db' => $admin->testDBRefs($admin->checkSelectDBRefs),
491  'group_db' => $admin->testDBRefs($admin->checkGroupDBRefs)
492  ));
493  }
494 
500  public function getModuleTemplate()
501  {
502  return $this->moduleTemplate;
503  }
504 
505 
506 }