[TASK] BACK_PATH DocumentTemplate
[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 TYPO3\CMS\Backend\Module\BaseScriptClass;
18 use TYPO3\CMS\Backend\Template\DocumentTemplate;
19 use TYPO3\CMS\Backend\Utility\IconUtility;
20 use TYPO3\CMS\Core\Database\QueryView;
21 use TYPO3\CMS\Core\Database\ReferenceIndex;
22 use TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
25 use TYPO3\CMS\Fluid\View\StandaloneView;
26
27 /**
28 * Script class for the DB int module
29 */
30 class DatabaseIntegrityView extends BaseScriptClass {
31
32 /**
33 * @var string
34 */
35 protected $formName = 'queryform';
36
37 /**
38 * The name of the module
39 *
40 * @var string
41 */
42 protected $moduleName = 'system_dbint';
43
44 /**
45 * @var StandaloneView
46 */
47 protected $view;
48
49 /**
50 * @var string
51 */
52 protected $templatePath = 'EXT:lowlevel/Resources/Private/Templates/Backend/';
53
54 /**
55 * Constructor
56 */
57 public function __construct() {
58 $this->getLanguageService()->includeLLFile('EXT:lowlevel/Resources/Private/Language/locallang.xlf');
59 $this->view = GeneralUtility::makeInstance(StandaloneView::class);
60 $this->view->getRequest()->setControllerExtensionName('lowlevel');
61 }
62
63 /**
64 * Initialization
65 *
66 * @return void
67 */
68 public function init() {
69 $this->MCONF['name'] = 'system_dbint';
70 $this->menuConfig();
71 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
72 $this->doc->setModuleTemplate('EXT:lowlevel/Resources/Private/Templates/dbint.html');
73 $this->doc->form = '<form action="" method="post" name="' . $this->formName . '">';
74 }
75
76 /**
77 * Configure menu
78 *
79 * @return void
80 */
81 public function menuConfig() {
82 $lang = $this->getLanguageService();
83 // MENU-ITEMS:
84 // If array, then it's a selector box menu
85 // If empty string it's just a variable, that'll be saved.
86 // Values NOT in this array will not be saved in the settings-array for the module.
87 $this->MOD_MENU = array(
88 'function' => array(
89 0 => $lang->getLL('menuTitle', TRUE),
90 'records' => $lang->getLL('recordStatistics', TRUE),
91 'relations' => $lang->getLL('databaseRelations', TRUE),
92 'search' => $lang->getLL('fullSearch', TRUE),
93 'refindex' => $lang->getLL('manageRefIndex', TRUE)
94 ),
95 'search' => array(
96 'raw' => $lang->getLL('rawSearch', TRUE),
97 'query' => $lang->getLL('advancedQuery', TRUE)
98 ),
99 'search_query_smallparts' => '',
100 'search_result_labels' => '',
101 'labels_noprefix' => '',
102 'options_sortlabel' => '',
103 'show_deleted' => '',
104 'queryConfig' => '',
105 // Current query
106 'queryTable' => '',
107 // Current table
108 'queryFields' => '',
109 // Current tableFields
110 'queryLimit' => '',
111 // Current limit
112 'queryOrder' => '',
113 // Current Order field
114 'queryOrderDesc' => '',
115 // Current Order field descending flag
116 'queryOrder2' => '',
117 // Current Order2 field
118 'queryOrder2Desc' => '',
119 // Current Order2 field descending flag
120 'queryGroup' => '',
121 // Current Group field
122 'storeArray' => '',
123 // Used to store the available Query config memory banks
124 'storeQueryConfigs' => '',
125 // Used to store the available Query configs in memory
126 'search_query_makeQuery' => array(
127 'all' => $lang->getLL('selectRecords', TRUE),
128 'count' => $lang->getLL('countResults', TRUE),
129 'explain' => $lang->getLL('explainQuery', TRUE),
130 'csv' => $lang->getLL('csvExport', TRUE)
131 ),
132 'sword' => ''
133 );
134 // CLEAN SETTINGS
135 $OLD_MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, '', $this->moduleName, 'ses');
136 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName, 'ses');
137 if (GeneralUtility::_GP('queryConfig')) {
138 $qA = GeneralUtility::_GP('queryConfig');
139 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, array('queryConfig' => serialize($qA)), $this->moduleName, 'ses');
140 }
141 $addConditionCheck = GeneralUtility::_GP('qG_ins');
142 $setLimitToStart = FALSE;
143 foreach ($OLD_MOD_SETTINGS as $key => $val) {
144 if (substr($key, 0, 5) == 'query' && $this->MOD_SETTINGS[$key] != $val && $key != 'queryLimit' && $key != 'use_listview') {
145 $setLimitToStart = TRUE;
146 if ($key == 'queryTable' && !$addConditionCheck) {
147 $this->MOD_SETTINGS['queryConfig'] = '';
148 }
149 }
150 if ($key == 'queryTable' && $this->MOD_SETTINGS[$key] != $val) {
151 $this->MOD_SETTINGS['queryFields'] = '';
152 }
153 }
154 if ($setLimitToStart) {
155 $currentLimit = explode(',', $this->MOD_SETTINGS['queryLimit']);
156 if ($currentLimit[1]) {
157 $this->MOD_SETTINGS['queryLimit'] = '0,' . $currentLimit[1];
158 } else {
159 $this->MOD_SETTINGS['queryLimit'] = '0';
160 }
161 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, $this->MOD_SETTINGS, $this->moduleName, 'ses');
162 }
163 }
164
165 /**
166 * Main functions, is rendering the content
167 *
168 * @return void
169 */
170 public function main() {
171 switch ($this->MOD_SETTINGS['function']) {
172 case 'search':
173 $templateFilename = 'CustomSearch.html';
174 $this->func_search();
175 break;
176 case 'records':
177 $templateFilename = 'RecordStatistics.html';
178 $this->func_records();
179 break;
180 case 'relations':
181 $templateFilename = 'Relations.html';
182 $this->func_relations();
183 break;
184 case 'refindex':
185 $templateFilename = 'ReferenceIndex.html';
186 $this->func_refindex();
187 break;
188 default:
189 $templateFilename = 'IntegrityOverview.html';
190 $this->func_default();
191 }
192 $this->view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePath . $templateFilename));
193 $this->content = $this->view->render();
194
195 // Setting up the buttons and markers for docheader
196 $docHeaderButtons = $this->getButtons();
197 $markers = array(
198 'CSH' => $docHeaderButtons['csh'],
199 'FUNC_MENU' => $this->getFuncMenu(),
200 'CONTENT' => $this->content
201 );
202 // Build the <body> for the module
203 $this->content = $this->doc->moduleBody(array(), $docHeaderButtons, $markers);
204 // Renders the module page
205 $this->content = $this->doc->render($this->getLanguageService()->getLL('title'), $this->content);
206 }
207
208 /**
209 * Print content
210 *
211 * @return void
212 */
213 public function printContent() {
214 echo $this->content;
215 }
216
217 /**
218 * Create the panel of buttons for submitting the form or otherwise perform operations.
219 *
220 * @return array All available buttons as an assoc. array
221 */
222 protected function getButtons() {
223 $buttons = array(
224 'csh' => '',
225 'shortcut' => ''
226 );
227 // Shortcut
228 if ($this->getBackendUser()->mayMakeShortcut()) {
229 $buttons['shortcut'] = $this->doc->makeShortcutIcon('', 'function,search,search_query_makeQuery', $this->moduleName);
230 }
231 return $buttons;
232 }
233
234 /**
235 * Create the function menu
236 *
237 * @return string HTML of the function menu
238 */
239 protected function getFuncMenu() {
240 return BackendUtility::getFuncMenu(0, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
241 }
242
243 /**
244 * Creates the overview menu.
245 *
246 * @return void
247 */
248 protected function func_default() {
249 $modules = array();
250 $availableModFuncs = array('records', 'relations', 'search', 'refindex');
251 foreach ($availableModFuncs as $modFunc) {
252 $modules[$modFunc] = BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=' . $modFunc;
253 }
254 $this->view->assign('availableFunctions', $modules);
255 }
256
257 /****************************
258 *
259 * Functionality implementation
260 *
261 ****************************/
262 /**
263 * Check and update reference index!
264 *
265 * @return void
266 */
267 public function func_refindex() {
268 $this->view->assign('PATH_typo3', PATH_typo3);
269
270 if (GeneralUtility::_GP('_update') || GeneralUtility::_GP('_check')) {
271 $testOnly = (bool)GeneralUtility::_GP('_check');
272 // Call the functionality
273 $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
274 list(,$bodyContent) = $refIndexObj->updateIndex($testOnly);
275 $this->view->assign('content', str_replace('##LF##', '<br />', $bodyContent));
276 }
277 }
278
279 /**
280 * Search (Full / Advanced)
281 *
282 * @return void
283 */
284 public function func_search() {
285 $lang = $this->getLanguageService();
286 $searchMode = $this->MOD_SETTINGS['search'];
287 $fullsearch = GeneralUtility::makeInstance(QueryView::class);
288 $fullsearch->setFormName($this->formName);
289 $submenu = '<div class="form-inline form-inline-spaced">';
290 $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search]', $searchMode, $this->MOD_MENU['search']);
291 if ($this->MOD_SETTINGS['search'] == 'query') {
292 $submenu .= BackendUtility::getDropdownMenu(0, 'SET[search_query_makeQuery]', $this->MOD_SETTINGS['search_query_makeQuery'], $this->MOD_MENU['search_query_makeQuery']) . '<br />';
293 }
294 $submenu .= '</div>';
295 if ($this->MOD_SETTINGS['search'] == 'query') {
296 $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>';
297 $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>';
298 $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>';
299 $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>';
300 $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>';
301 }
302 $this->view->assign('submenu', $submenu);
303 $this->view->assign('searchMode', $searchMode);
304 switch ($searchMode) {
305 case 'query':
306 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Core/QueryGenerator');
307 $this->view->assign('queryMaker', $fullsearch->queryMaker());
308 break;
309 case 'raw':
310 default:
311 $this->view->assign('searchOptions', $fullsearch->form());
312 $this->view->assign('results', $fullsearch->search());
313 }
314 }
315
316 /**
317 * Records overview
318 *
319 * @return void
320 */
321 public function func_records() {
322
323 /** @var $admin DatabaseIntegrityCheck */
324 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
325 $admin->genTree(0);
326
327 // Pages stat
328 $pageStatistic = array(
329 'total_pages' => array(
330 'icon' => IconUtility::getSpriteIconForRecord('pages', array()),
331 'count' => count($admin->page_idArray)
332 ),
333 'hidden_pages' => array(
334 'icon' => IconUtility::getSpriteIconForRecord('pages', array('hidden' => 1)),
335 'count' => $admin->recStats['hidden']
336 ),
337 'deleted_pages' => array(
338 'icon' => IconUtility::getSpriteIconForRecord('pages', array('deleted' => 1)),
339 'count' => count($admin->recStats['deleted']['pages'])
340 )
341 );
342
343 $lang = $this->getLanguageService();
344
345 // Doktype
346 $doktypes = array();
347 $doktype = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
348 if (is_array($doktype)) {
349 foreach ($doktype as $setup) {
350 if ($setup[1] != '--div--') {
351 $doktypes[] = array(
352 'icon' => IconUtility::getSpriteIconForRecord('pages', array('doktype' => $setup[1])),
353 'title' => $lang->sL($setup[0]) . ' (' . $setup[1] . ')',
354 'count' => (int)$admin->recStats['doktype'][$setup[1]]
355 );
356 }
357 }
358 }
359
360 // Tables and lost records
361 $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
362 $id_list = rtrim($id_list, ',');
363 $admin->lostRecords($id_list);
364 if ($admin->fixLostRecord(GeneralUtility::_GET('fixLostRecords_table'), GeneralUtility::_GET('fixLostRecords_uid'))) {
365 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
366 $admin->genTree(0);
367 $id_list = '-1,0,' . implode(',', array_keys($admin->page_idArray));
368 $id_list = rtrim($id_list, ',');
369 $admin->lostRecords($id_list);
370 }
371 $tableStatistic = array();
372 $countArr = $admin->countRecords($id_list);
373 if (is_array($GLOBALS['TCA'])) {
374 foreach ($GLOBALS['TCA'] as $t => $value) {
375 if ($GLOBALS['TCA'][$t]['ctrl']['hideTable']) {
376 continue;
377 }
378 if ($t === 'pages' && $admin->lostPagesList !== '') {
379 $lostRecordCount = count(explode(',', $admin->lostPagesList));
380 } else {
381 $lostRecordCount = count($admin->lRecords[$t]);
382 }
383 if ($countArr['all'][$t]) {
384 $theNumberOfRe = (int)$countArr['non_deleted'][$t] . '/' . $lostRecordCount;
385 } else {
386 $theNumberOfRe = '';
387 }
388 $lr = '';
389 if (is_array($admin->lRecords[$t])) {
390 foreach ($admin->lRecords[$t] as $data) {
391 if (!GeneralUtility::inList($admin->lostPagesList, $data['pid'])) {
392 $lr .= '<div class="record"><a href="' . htmlspecialchars((BackendUtility::getModuleUrl('system_dbint') . '&SET[function]=records&fixLostRecords_table=' . $t . '&fixLostRecords_uid=' . $data['uid'])) . '">' . IconUtility::getSpriteIcon('status-dialog-error', array('title' => $lang->getLL('fixLostRecord'))) . '</a>uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
393 } else {
394 $lr .= '<div class="record-noicon">uid:' . $data['uid'] . ', pid:' . $data['pid'] . ', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data['title']), 20)) . '</div>';
395 }
396 }
397 }
398 $tableStatistic[$t] = array(
399 'icon' => IconUtility::getSpriteIconForRecord($t, array()),
400 'title' => $lang->sL($GLOBALS['TCA'][$t]['ctrl']['title']),
401 'count' => $theNumberOfRe,
402 'lostRecords' => $lr
403 );
404 }
405 }
406
407 $this->view->assignMultiple(array(
408 'pages' => $pageStatistic,
409 'doktypes' => $doktypes,
410 'tables' => $tableStatistic
411 ));
412 }
413
414 /**
415 * Show list references
416 *
417 * @return void
418 */
419 public function func_relations() {
420 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
421 $fkey_arrays = $admin->getGroupFields('');
422 $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays);
423 $fileTest = $admin->testFileRefs();
424
425 if (is_array($fileTest['noFile'])) {
426 ksort($fileTest['noFile']);
427 }
428 $this->view->assignMultiple(array(
429 'files' => $fileTest,
430 'select_db' => $admin->testDBRefs($admin->checkSelectDBRefs),
431 'group_db' => $admin->testDBRefs($admin->checkGroupDBRefs)
432 ));
433 }
434
435 }