[TASK] Removed deprecated code from lowlevel and utility functions
[Packages/TYPO3.CMS.git] / typo3 / sysext / lowlevel / Classes / View / DatabaseIntegrityView.php
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
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\BaseScriptClass;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Database\QueryView;
24 use TYPO3\CMS\Core\Database\ReferenceIndex;
25 use TYPO3\CMS\Core\Imaging\Icon;
26 use TYPO3\CMS\Core\Imaging\IconFactory;
27 use TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Fluid\View\StandaloneView;
30
31 /**
32 * Script class for the DB int module
33 */
34 class DatabaseIntegrityView extends BaseScriptClass
35 {
36 /**
37 * @var string
38 */
39 protected $formName = 'queryform';
40
41 /**
42 * The name of the module
43 *
44 * @var string
45 */
46 protected $moduleName = 'system_dbint';
47
48 /**
49 * @var StandaloneView
50 */
51 protected $view;
52
53 /**
54 * @var string
55 */
56 protected $templatePath = 'EXT:lowlevel/Resources/Private/Templates/Backend/';
57
58 /**
59 * @var IconFactory
60 */
61 protected $iconFactory;
62
63 /**
64 * ModuleTemplate Container
65 *
66 * @var ModuleTemplate
67 */
68 protected $moduleTemplate;
69
70 /**
71 * Constructor
72 */
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
81 /**
82 * Initialization
83 *
84 * @return void
85 */
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
102 /**
103 * Configure menu
104 *
105 * @return void
106 */
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
192 /**
193 * Main functions, is rendering the content
194 *
195 * @return void
196 */
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
237 /**
238 * Injects the request object for the current request or subrequest
239 * Simply calls main() and init() and outputs the content
240 *
241 * @param ServerRequestInterface $request the current request
242 * @param ResponseInterface $response
243 * @return ResponseInterface the response with the content
244 */
245 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
246 {
247 $GLOBALS['SOBE'] = $this;
248 $this->init();
249 $this->main();
250
251 $this->moduleTemplate->setContent($this->content);
252 $response->getBody()->write($this->moduleTemplate->renderContent());
253 return $response;
254 }
255
256 /**
257 * Generates the action menu
258 */
259 protected function getModuleMenu()
260 {
261 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
262 $menu->setIdentifier('DatabaseJumpMenu');
263
264 foreach ($this->MOD_MENU['function'] as $controller => $title) {
265 $item = $menu
266 ->makeMenuItem()
267 ->setHref(
268 BackendUtility::getModuleUrl(
269 $this->moduleName,
270 [
271 'id' => $this->id,
272 'SET' => [
273 'function' => $controller
274 ]
275 ]
276 )
277 )
278 ->setTitle($title);
279 if ($controller === $this->MOD_SETTINGS['function']) {
280 $item->setActive(true);
281 }
282 $menu->addMenuItem($item);
283 }
284 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
285 }
286
287 /**
288 * Creates the overview menu.
289 *
290 * @return void
291 */
292 protected function func_default()
293 {
294 $modules = array();
295 $availableModFuncs = array('records', 'relations', 'search', 'refindex');
296 foreach ($availableModFuncs as $modFunc) {
297 $modules[$modFunc] = BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=' . $modFunc;
298 }
299 $this->view->assign('availableFunctions', $modules);
300 }
301
302 /****************************
303 *
304 * Functionality implementation
305 *
306 ****************************/
307 /**
308 * Check and update reference index!
309 *
310 * @return void
311 */
312 public function func_refindex()
313 {
314 $this->view->assign('PATH_typo3', PATH_typo3);
315
316 if (GeneralUtility::_GP('_update') || GeneralUtility::_GP('_check')) {
317 $testOnly = (bool)GeneralUtility::_GP('_check');
318 // Call the functionality
319 $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
320 list(, $bodyContent) = $refIndexObj->updateIndex($testOnly);
321 $this->view->assign('content', str_replace('##LF##', '<br />', $bodyContent));
322 }
323 }
324
325 /**
326 * Search (Full / Advanced)
327 *
328 * @return void
329 */
330 public function func_search()
331 {
332 $lang = $this->getLanguageService();
333 $searchMode = $this->MOD_SETTINGS['search'];
334 $fullsearch = GeneralUtility::makeInstance(QueryView::class);
335 $fullsearch->setFormName($this->formName);
336 $submenu = '<div class="form-inline form-inline-spaced">';
337 $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search]', $searchMode, $this->MOD_MENU['search']);
338 if ($this->MOD_SETTINGS['search'] == 'query') {
339 $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search_query_makeQuery]', $this->MOD_SETTINGS['search_query_makeQuery'], $this->MOD_MENU['search_query_makeQuery']) . '<br />';
340 }
341 $submenu .= '</div>';
342 if ($this->MOD_SETTINGS['search'] == 'query') {
343 $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>';
344 $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>';
345 $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>';
346 $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>';
347 $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>';
348 }
349 $this->view->assign('submenu', $submenu);
350 $this->view->assign('searchMode', $searchMode);
351 switch ($searchMode) {
352 case 'query':
353 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Core/QueryGenerator');
354 $this->view->assign('queryMaker', $fullsearch->queryMaker());
355 break;
356 case 'raw':
357 default:
358 $this->view->assign('searchOptions', $fullsearch->form());
359 $this->view->assign('results', $fullsearch->search());
360 }
361 }
362
363 /**
364 * Records overview
365 *
366 * @return void
367 */
368 public function func_records()
369 {
370 /** @var $admin DatabaseIntegrityCheck */
371 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
372 $admin->genTree(0);
373
374 // Pages stat
375 $pageStatistic = array(
376 'total_pages' => array(
377 'icon' => $this->iconFactory->getIconForRecord('pages', array(), Icon::SIZE_SMALL)->render(),
378 'count' => count($admin->page_idArray)
379 ),
380 'hidden_pages' => array(
381 'icon' => $this->iconFactory->getIconForRecord('pages', array('hidden' => 1), Icon::SIZE_SMALL)->render(),
382 'count' => $admin->recStats['hidden']
383 ),
384 'deleted_pages' => array(
385 'icon' => $this->iconFactory->getIconForRecord('pages', array('deleted' => 1), Icon::SIZE_SMALL)->render(),
386 'count' => count($admin->recStats['deleted']['pages'])
387 )
388 );
389
390 $lang = $this->getLanguageService();
391
392 // Doktype
393 $doktypes = array();
394 $doktype = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
395 if (is_array($doktype)) {
396 foreach ($doktype as $setup) {
397 if ($setup[1] != '--div--') {
398 $doktypes[] = array(
399 'icon' => $this->iconFactory->getIconForRecord('pages', array('doktype' => $setup[1]), Icon::SIZE_SMALL)->render(),
400 'title' => $lang->sL($setup[0]) . ' (' . $setup[1] . ')',
401 'count' => (int)$admin->recStats['doktype'][$setup[1]]
402 );
403 }
404 }
405 }
406
407 // Tables and lost records
408 $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
409 $id_list = rtrim($id_list, ',');
410 $admin->lostRecords($id_list);
411 if ($admin->fixLostRecord(GeneralUtility::_GET('fixLostRecords_table'), GeneralUtility::_GET('fixLostRecords_uid'))) {
412 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
413 $admin->genTree(0);
414 $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
415 $id_list = rtrim($id_list, ',');
416 $admin->lostRecords($id_list);
417 }
418 $tableStatistic = array();
419 $countArr = $admin->countRecords($id_list);
420 if (is_array($GLOBALS['TCA'])) {
421 foreach ($GLOBALS['TCA'] as $t => $value) {
422 if ($GLOBALS['TCA'][$t]['ctrl']['hideTable']) {
423 continue;
424 }
425 if ($t === 'pages' && $admin->lostPagesList !== '') {
426 $lostRecordCount = count(explode(',', $admin->lostPagesList));
427 } else {
428 $lostRecordCount = count($admin->lRecords[$t]);
429 }
430 if ($countArr['all'][$t]) {
431 $theNumberOfRe = (int)$countArr['non_deleted'][$t] . '/' . $lostRecordCount;
432 } else {
433 $theNumberOfRe = '';
434 }
435 $lr = '';
436 if (is_array($admin->lRecords[$t])) {
437 foreach ($admin->lRecords[$t] as $data) {
438 if (!GeneralUtility::inList($admin->lostPagesList, $data['pid'])) {
439 $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>';
440 } else {
441 $lr .= '<div class="record-noicon">uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
442 }
443 }
444 }
445 $tableStatistic[$t] = array(
446 'icon' => $this->iconFactory->getIconForRecord($t, array(), Icon::SIZE_SMALL)->render(),
447 'title' => $lang->sL($GLOBALS['TCA'][$t]['ctrl']['title']),
448 'count' => $theNumberOfRe,
449 'lostRecords' => $lr
450 );
451 }
452 }
453
454 $this->view->assignMultiple(array(
455 'pages' => $pageStatistic,
456 'doktypes' => $doktypes,
457 'tables' => $tableStatistic
458 ));
459 }
460
461 /**
462 * Show list references
463 *
464 * @return void
465 */
466 public function func_relations()
467 {
468 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
469 $fkey_arrays = $admin->getGroupFields('');
470 $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays);
471 $fileTest = $admin->testFileRefs();
472
473 if (is_array($fileTest['noFile'])) {
474 ksort($fileTest['noFile']);
475 }
476 $this->view->assignMultiple(array(
477 'files' => $fileTest,
478 'select_db' => $admin->testDBRefs($admin->checkSelectDBRefs),
479 'group_db' => $admin->testDBRefs($admin->checkGroupDBRefs)
480 ));
481 }
482
483 /**
484 * Returns the ModuleTemplate container
485 *
486 * @return ModuleTemplate
487 */
488 public function getModuleTemplate()
489 {
490 return $this->moduleTemplate;
491 }
492 }