[TASK] Fix CGL errors
[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\Core\Database\QueryView;
23 use TYPO3\CMS\Core\Database\ReferenceIndex;
24 use TYPO3\CMS\Core\Imaging\Icon;
25 use TYPO3\CMS\Core\Imaging\IconFactory;
26 use TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Backend\Utility\BackendUtility;
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 * Print content
239 *
240 * @return void
241 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
242 */
243 public function printContent()
244 {
245 GeneralUtility::logDeprecatedFunction();
246 echo $this->content;
247 }
248
249 /**
250 * Injects the request object for the current request or subrequest
251 * Simply calls main() and init() and outputs the content
252 *
253 * @param ServerRequestInterface $request the current request
254 * @param ResponseInterface $response
255 * @return ResponseInterface the response with the content
256 */
257 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
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
268 /**
269 * Generates the action menu
270 */
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
299 /**
300 * Creates the overview menu.
301 *
302 * @return void
303 */
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 ****************************/
319 /**
320 * Check and update reference index!
321 *
322 * @return void
323 */
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
337 /**
338 * Search (Full / Advanced)
339 *
340 * @return void
341 */
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
375 /**
376 * Records overview
377 *
378 * @return void
379 */
380 public function func_records()
381 {
382 /** @var $admin DatabaseIntegrityCheck */
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
473 /**
474 * Show list references
475 *
476 * @return void
477 */
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
495 /**
496 * Returns the ModuleTemplate container
497 *
498 * @return ModuleTemplate
499 */
500 public function getModuleTemplate()
501 {
502 return $this->moduleTemplate;
503 }
504 }