TYPO3 CMS  TYPO3_8-7
DatabaseIntegrityView.php
Go to the documentation of this file.
1 <?php
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 
32 
37 {
41  protected $formName = 'queryform';
42 
48  protected $moduleName = 'system_dbint';
49 
53  protected $view;
54 
58  protected $templatePath = 'EXT:lowlevel/Resources/Private/Templates/Backend/';
59 
63  protected $iconFactory;
64 
70  protected $moduleTemplate;
71 
75  public function __construct()
76  {
77  $this->getLanguageService()->includeLLFile('EXT:lowlevel/Resources/Private/Language/locallang.xlf');
78  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
79  $this->view = GeneralUtility::makeInstance(StandaloneView::class);
80  $this->view->getRequest()->setControllerExtensionName('lowlevel');
81  }
82 
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 
105  public function menuConfig()
106  {
107  $lang = $this->getLanguageService();
108  // MENU-ITEMS:
109  // If array, then it's a selector box menu
110  // If empty string it's just a variable, that'll be saved.
111  // Values NOT in this array will not be saved in the settings-array for the module.
112  $this->MOD_MENU = [
113  'function' => [
114  0 => htmlspecialchars($lang->getLL('menuTitle')),
115  'records' => htmlspecialchars($lang->getLL('recordStatistics')),
116  'relations' => htmlspecialchars($lang->getLL('databaseRelations')),
117  'search' => htmlspecialchars($lang->getLL('fullSearch')),
118  'refindex' => htmlspecialchars($lang->getLL('manageRefIndex'))
119  ],
120  'search' => [
121  'raw' => htmlspecialchars($lang->getLL('rawSearch')),
122  'query' => htmlspecialchars($lang->getLL('advancedQuery'))
123  ],
124  'search_query_smallparts' => '',
125  'search_result_labels' => '',
126  'labels_noprefix' => '',
127  'options_sortlabel' => '',
128  'show_deleted' => '',
129  'queryConfig' => '',
130  // Current query
131  'queryTable' => '',
132  // Current table
133  'queryFields' => '',
134  // Current tableFields
135  'queryLimit' => '',
136  // Current limit
137  'queryOrder' => '',
138  // Current Order field
139  'queryOrderDesc' => '',
140  // Current Order field descending flag
141  'queryOrder2' => '',
142  // Current Order2 field
143  'queryOrder2Desc' => '',
144  // Current Order2 field descending flag
145  'queryGroup' => '',
146  // Current Group field
147  'storeArray' => '',
148  // Used to store the available Query config memory banks
149  'storeQueryConfigs' => '',
150  // Used to store the available Query configs in memory
151  'search_query_makeQuery' => [
152  'all' => htmlspecialchars($lang->getLL('selectRecords')),
153  'count' => htmlspecialchars($lang->getLL('countResults')),
154  'explain' => htmlspecialchars($lang->getLL('explainQuery')),
155  'csv' => htmlspecialchars($lang->getLL('csvExport'))
156  ],
157  'sword' => ''
158  ];
159  // CLEAN SETTINGS
160  $OLD_MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, '', $this->moduleName, 'ses');
161  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName, 'ses');
162  if (GeneralUtility::_GP('queryConfig')) {
163  $qA = GeneralUtility::_GP('queryConfig');
164  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, ['queryConfig' => serialize($qA)], $this->moduleName, 'ses');
165  }
166  $addConditionCheck = GeneralUtility::_GP('qG_ins');
167  $setLimitToStart = false;
168  foreach ($OLD_MOD_SETTINGS as $key => $val) {
169  if (substr($key, 0, 5) === 'query' && $this->MOD_SETTINGS[$key] != $val && $key !== 'queryLimit' && $key !== 'use_listview') {
170  $setLimitToStart = true;
171  if ($key === 'queryTable' && !$addConditionCheck) {
172  $this->MOD_SETTINGS['queryConfig'] = '';
173  }
174  }
175  if ($key === 'queryTable' && $this->MOD_SETTINGS[$key] != $val) {
176  $this->MOD_SETTINGS['queryFields'] = '';
177  }
178  }
179  if ($setLimitToStart) {
180  $currentLimit = explode(',', $this->MOD_SETTINGS['queryLimit']);
181  if ($currentLimit[1]) {
182  $this->MOD_SETTINGS['queryLimit'] = '0,' . $currentLimit[1];
183  } else {
184  $this->MOD_SETTINGS['queryLimit'] = '0';
185  }
186  $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $this->MOD_SETTINGS, $this->moduleName, 'ses');
187  }
188  }
189 
193  public function main()
194  {
195  switch ($this->MOD_SETTINGS['function']) {
196  case 'search':
197  $templateFilename = 'CustomSearch.html';
198  $this->func_search();
199  break;
200  case 'records':
201  $templateFilename = 'RecordStatistics.html';
202  $this->func_records();
203  break;
204  case 'relations':
205  $templateFilename = 'Relations.html';
206  $this->func_relations();
207  break;
208  case 'refindex':
209  $templateFilename = 'ReferenceIndex.html';
210  $this->func_refindex();
211  break;
212  default:
213  $templateFilename = 'IntegrityOverview.html';
214  $this->func_default();
215  }
216  $this->view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePath . $templateFilename));
217  $this->content = '<form action="" method="post" id="DatabaseIntegrityView" name="' . $this->formName . '">';
218  $this->content .= $this->view->render();
219  $this->content .= '</form>';
220 
221  // Setting up the shortcut button for docheader
222  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
223  // Shortcut
224  $shortCutButton = $buttonBar->makeShortcutButton()
225  ->setModuleName($this->moduleName)
226  ->setDisplayName($this->MOD_MENU['function'][$this->MOD_SETTINGS['function']])
227  ->setSetVariables(['function', 'search', 'search_query_makeQuery']);
228  $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT, 2);
229 
230  $this->getModuleMenu();
231  }
232 
241  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
242  {
243  $GLOBALS['SOBE'] = $this;
244  $this->init();
245  $this->main();
246 
247  $this->moduleTemplate->setContent($this->content);
248  $response->getBody()->write($this->moduleTemplate->renderContent());
249  return $response;
250  }
251 
255  protected function getModuleMenu()
256  {
257  $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
258  $menu->setIdentifier('DatabaseJumpMenu');
259 
260  foreach ($this->MOD_MENU['function'] as $controller => $title) {
261  $item = $menu
262  ->makeMenuItem()
263  ->setHref(
264  BackendUtility::getModuleUrl(
265  $this->moduleName,
266  [
267  'id' => $this->id,
268  'SET' => [
269  'function' => $controller
270  ]
271  ]
272  )
273  )
274  ->setTitle($title);
275  if ($controller === $this->MOD_SETTINGS['function']) {
276  $item->setActive(true);
277  }
278  $menu->addMenuItem($item);
279  }
280  $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
281  }
282 
286  protected function func_default()
287  {
288  $modules = [];
289  $availableModFuncs = ['records', 'relations', 'search', 'refindex'];
290  foreach ($availableModFuncs as $modFunc) {
291  $modules[$modFunc] = BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=' . $modFunc;
292  }
293  $this->view->assign('availableFunctions', $modules);
294  }
295 
296  /****************************
297  *
298  * Functionality implementation
299  *
300  ****************************/
304  public function func_refindex()
305  {
306  $readmeLocation = ExtensionManagementUtility::extPath('lowlevel', 'README.rst');
307  $this->view->assign('ReadmeLink', PathUtility::getAbsoluteWebPath($readmeLocation));
308  $this->view->assign('ReadmeLocation', $readmeLocation);
309  $this->view->assign('binaryPath', ExtensionManagementUtility::extPath('core', 'bin/typo3'));
310 
311  if (GeneralUtility::_GP('_update') || GeneralUtility::_GP('_check')) {
312  $testOnly = (bool)GeneralUtility::_GP('_check');
313  // Call the functionality
314  $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
315  list(, $bodyContent) = $refIndexObj->updateIndex($testOnly);
316  $this->view->assign('content', str_replace('##LF##', '<br />', $bodyContent));
317  }
318  }
319 
323  public function func_search()
324  {
325  $lang = $this->getLanguageService();
326  $searchMode = $this->MOD_SETTINGS['search'];
327  $fullsearch = GeneralUtility::makeInstance(QueryView::class);
328  $fullsearch->setFormName($this->formName);
329  $submenu = '<div class="form-inline form-inline-spaced">';
330  $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search]', $searchMode, $this->MOD_MENU['search']);
331  if ($this->MOD_SETTINGS['search'] === 'query') {
332  $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search_query_makeQuery]', $this->MOD_SETTINGS['search_query_makeQuery'], $this->MOD_MENU['search_query_makeQuery']) . '<br />';
333  }
334  $submenu .= '</div>';
335  if ($this->MOD_SETTINGS['search'] === 'query') {
336  $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>';
337  $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>';
338  $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>';
339  $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>';
340  $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>';
341  }
342  $this->view->assign('submenu', $submenu);
343  $this->view->assign('searchMode', $searchMode);
344  switch ($searchMode) {
345  case 'query':
346  $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Lowlevel/QueryGenerator');
347  $this->view->assign('queryMaker', $fullsearch->queryMaker());
348  break;
349  case 'raw':
350  default:
351  $this->view->assign('searchOptions', $fullsearch->form());
352  $this->view->assign('results', $fullsearch->search());
353  }
354  }
355 
359  public function func_records()
360  {
362  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
363  $admin->genTree(0);
364 
365  // Pages stat
366  $pageStatistic = [
367  'total_pages' => [
368  'icon' => $this->iconFactory->getIconForRecord('pages', [], Icon::SIZE_SMALL)->render(),
369  'count' => count($admin->page_idArray)
370  ],
371  'hidden_pages' => [
372  'icon' => $this->iconFactory->getIconForRecord('pages', ['hidden' => 1], Icon::SIZE_SMALL)->render(),
373  'count' => $admin->recStats['hidden']
374  ],
375  'deleted_pages' => [
376  'icon' => $this->iconFactory->getIconForRecord('pages', ['deleted' => 1], Icon::SIZE_SMALL)->render(),
377  'count' => isset($admin->recStats['deleted']['pages']) ? count($admin->recStats['deleted']['pages']) : 0
378  ]
379  ];
380 
381  $lang = $this->getLanguageService();
382 
383  // Doktype
384  $doktypes = [];
385  $doktype = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
386  if (is_array($doktype)) {
387  foreach ($doktype as $setup) {
388  if ($setup[1] !== '--div--') {
389  $doktypes[] = [
390  'icon' => $this->iconFactory->getIconForRecord('pages', ['doktype' => $setup[1]], Icon::SIZE_SMALL)->render(),
391  'title' => $lang->sL($setup[0]) . ' (' . $setup[1] . ')',
392  'count' => (int)$admin->recStats['doktype'][$setup[1]]
393  ];
394  }
395  }
396  }
397 
398  // Tables and lost records
399  $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
400  $id_list = rtrim($id_list, ',');
401  $admin->lostRecords($id_list);
402  if ($admin->fixLostRecord(GeneralUtility::_GET('fixLostRecords_table'), GeneralUtility::_GET('fixLostRecords_uid'))) {
403  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
404  $admin->genTree(0);
405  $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
406  $id_list = rtrim($id_list, ',');
407  $admin->lostRecords($id_list);
408  }
409  $tableStatistic = [];
410  $countArr = $admin->countRecords($id_list);
411  if (is_array($GLOBALS['TCA'])) {
412  foreach ($GLOBALS['TCA'] as $t => $value) {
413  if ($GLOBALS['TCA'][$t]['ctrl']['hideTable']) {
414  continue;
415  }
416  if ($t === 'pages' && $admin->lostPagesList !== '') {
417  $lostRecordCount = count(explode(',', $admin->lostPagesList));
418  } else {
419  $lostRecordCount = isset($admin->lRecords[$t]) ? count($admin->lRecords[$t]) : 0;
420  }
421  if ($countArr['all'][$t]) {
422  $theNumberOfRe = (int)$countArr['non_deleted'][$t] . '/' . $lostRecordCount;
423  } else {
424  $theNumberOfRe = '';
425  }
426  $lr = '';
427  if (is_array($admin->lRecords[$t])) {
428  foreach ($admin->lRecords[$t] as $data) {
429  if (!GeneralUtility::inList($admin->lostPagesList, $data['pid'])) {
430  $lr .= '<div class="record"><a href="' . htmlspecialchars((BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=records&fixLostRecords_table=' . $t . '&fixLostRecords_uid=' . $data['uid'])) . '" title="' . htmlspecialchars($lang->getLL('fixLostRecord')) . '">' . $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>';
431  } else {
432  $lr .= '<div class="record-noicon">uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
433  }
434  }
435  }
436  $tableStatistic[$t] = [
437  'icon' => $this->iconFactory->getIconForRecord($t, [], Icon::SIZE_SMALL)->render(),
438  'title' => $lang->sL($GLOBALS['TCA'][$t]['ctrl']['title']),
439  'count' => $theNumberOfRe,
440  'lostRecords' => $lr
441  ];
442  }
443  }
444 
445  $this->view->assignMultiple([
446  'pages' => $pageStatistic,
447  'doktypes' => $doktypes,
448  'tables' => $tableStatistic
449  ]);
450  }
451 
455  public function func_relations()
456  {
457  $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
458  $fkey_arrays = $admin->getGroupFields('');
459  $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays);
460  $fileTest = $admin->testFileRefs();
461 
462  if (is_array($fileTest['noFile'])) {
463  ksort($fileTest['noFile']);
464  }
465  $this->view->assignMultiple([
466  'files' => $fileTest,
467  'select_db' => $admin->testDBRefs($admin->checkSelectDBRefs),
468  'group_db' => $admin->testDBRefs($admin->checkGroupDBRefs)
469  ]);
470  }
471 
477  public function getModuleTemplate()
478  {
479  return $this->moduleTemplate;
480  }
481 }
static getModuleData( $MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
static getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:40
static getFileAbsFileName($filename, $_=null, $_2=null)
mainAction(ServerRequestInterface $request, ResponseInterface $response)
static makeInstance($className,... $constructorArguments)
static getFuncCheck( $mainParams, $elementName, $currentValue, $script='', $addParams='', $tagParams='')
static fixed_lgd_cs($string, $chars, $appendString='...')
static getDropdownMenu( $mainParams, $elementName, $currentValue, $menuItems, $script='', $addParams='')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']