17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
61 protected $templatePath =
'EXT:lowlevel/Resources/Private/Templates/Backend/';
82 'name' =>
'system_dbint',
110 public function mainAction(ServerRequestInterface $request): ResponseInterface
113 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
114 $this->view = GeneralUtility::makeInstance(StandaloneView::class);
115 $this->view->getRequest()->setControllerExtensionName(
'lowlevel');
118 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
119 $this->moduleTemplate->addJavaScriptCode(
122 function jumpToUrl(URL) {
123 window.location.href = URL;
129 switch ($this->MOD_SETTINGS[
'function']) {
131 $templateFilename =
'CustomSearch.html';
135 $templateFilename =
'RecordStatistics.html';
139 $templateFilename =
'Relations.html';
143 $templateFilename =
'ReferenceIndex.html';
147 $templateFilename =
'IntegrityOverview.html';
150 $this->view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePath . $templateFilename));
151 $content =
'<form action="" method="post" id="DatabaseIntegrityView" name="' . $this->formName .
'">';
152 $content .= $this->view->render();
153 $content .=
'</form>';
156 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
158 $shortCutButton = $buttonBar->makeShortcutButton()
159 ->setModuleName($this->moduleName)
160 ->setDisplayName($this->MOD_MENU[
'function'][$this->MOD_SETTINGS[
'function']])
161 ->setSetVariables([
'function',
'search',
'search_query_makeQuery']);
166 $this->moduleTemplate->setContent($content);
167 return new HtmlResponse($this->moduleTemplate->renderContent());
182 0 => htmlspecialchars($lang->getLL(
'menuTitle')),
183 'records' => htmlspecialchars($lang->getLL(
'recordStatistics')),
184 'relations' => htmlspecialchars($lang->getLL(
'databaseRelations')),
185 'search' => htmlspecialchars($lang->getLL(
'fullSearch')),
186 'refindex' => htmlspecialchars($lang->getLL(
'manageRefIndex'))
189 'raw' => htmlspecialchars($lang->getLL(
'rawSearch')),
190 'query' => htmlspecialchars($lang->getLL(
'advancedQuery'))
192 'search_query_smallparts' =>
'',
193 'search_result_labels' =>
'',
194 'labels_noprefix' =>
'',
195 'options_sortlabel' =>
'',
196 'show_deleted' =>
'',
207 'queryOrderDesc' =>
'',
211 'queryOrder2Desc' =>
'',
217 'storeQueryConfigs' =>
'',
219 'search_query_makeQuery' => [
220 'all' => htmlspecialchars($lang->getLL(
'selectRecords')),
221 'count' => htmlspecialchars($lang->getLL(
'countResults')),
222 'explain' => htmlspecialchars($lang->getLL(
'explainQuery')),
223 'csv' => htmlspecialchars($lang->getLL(
'csvExport'))
230 if (GeneralUtility::_GP(
'queryConfig')) {
231 $qA = GeneralUtility::_GP(
'queryConfig');
234 $addConditionCheck = GeneralUtility::_GP(
'qG_ins');
235 $setLimitToStart =
false;
236 foreach ($OLD_MOD_SETTINGS as $key => $val) {
237 if (strpos($key,
'query') === 0 && $this->MOD_SETTINGS[$key] != $val && $key !==
'queryLimit' && $key !==
'use_listview') {
238 $setLimitToStart =
true;
239 if ($key ===
'queryTable' && !$addConditionCheck) {
240 $this->MOD_SETTINGS[
'queryConfig'] =
'';
243 if ($key ===
'queryTable' && $this->MOD_SETTINGS[$key] != $val) {
244 $this->MOD_SETTINGS[
'queryFields'] =
'';
247 if ($setLimitToStart) {
248 $currentLimit = explode(
',', $this->MOD_SETTINGS[
'queryLimit']);
249 if ($currentLimit[1]) {
250 $this->MOD_SETTINGS[
'queryLimit'] =
'0,' . $currentLimit[1];
252 $this->MOD_SETTINGS[
'queryLimit'] =
'0';
263 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
264 $menu->setIdentifier(
'DatabaseJumpMenu');
266 $uriBuilder = GeneralUtility::makeInstance(\
TYPO3\CMS\Backend\Routing\UriBuilder::class);
267 foreach ($this->MOD_MENU[
'function'] as $controller => $title) {
271 (
string)$uriBuilder->buildUriFromRoute(
276 'function' => $controller
282 if ($controller === $this->MOD_SETTINGS[
'function']) {
283 $item->setActive(
true);
285 $menu->addMenuItem($item);
287 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
296 $availableModFuncs = [
'records',
'relations',
'search',
'refindex'];
298 $uriBuilder = GeneralUtility::makeInstance(\
TYPO3\CMS\Backend\Routing\UriBuilder::class);
299 foreach ($availableModFuncs as $modFunc) {
300 $modules[$modFunc] = (string)$uriBuilder->buildUriFromRoute(
'system_dbint') .
'&SET[function]=' . $modFunc;
302 $this->view->assign(
'availableFunctions', $modules);
317 $this->view->assign(
'ReadmeLocation', $readmeLocation);
320 if (GeneralUtility::_GP(
'_update') || GeneralUtility::_GP(
'_check')) {
321 $testOnly = (bool)GeneralUtility::_GP(
'_check');
323 $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
324 $refIndexObj->enableRuntimeCache();
325 list(, $bodyContent) = $refIndexObj->updateIndex($testOnly);
326 $this->view->assign(
'content', str_replace(
'##LF##',
'<br />', $bodyContent));
336 $searchMode = $this->MOD_SETTINGS[
'search'];
337 $fullsearch = GeneralUtility::makeInstance(QueryView::class, $this->MOD_SETTINGS, $this->MOD_MENU, $this->moduleName);
338 $fullsearch->setFormName($this->formName);
339 $submenu =
'<div class="form-inline form-inline-spaced">';
341 if ($this->MOD_SETTINGS[
'search'] ===
'query') {
342 $submenu .=
BackendUtility::getDropdownMenu(0,
'SET[search_query_makeQuery]', $this->MOD_SETTINGS[
'search_query_makeQuery'], $this->MOD_MENU[
'search_query_makeQuery']) .
'<br />';
344 $submenu .=
'</div>';
345 if ($this->MOD_SETTINGS[
'search'] ===
'query') {
346 $submenu .=
'<div class="checkbox"><label for="checkSearch_query_smallparts">' .
BackendUtility::getFuncCheck(0,
'SET[search_query_smallparts]', $this->MOD_SETTINGS[
'search_query_smallparts'],
'',
'',
'id="checkSearch_query_smallparts"') . $lang->getLL(
'showSQL') .
'</label></div>';
347 $submenu .=
'<div class="checkbox"><label for="checkSearch_result_labels">' .
BackendUtility::getFuncCheck(0,
'SET[search_result_labels]', $this->MOD_SETTINGS[
'search_result_labels'],
'',
'',
'id="checkSearch_result_labels"') . $lang->getLL(
'useFormattedStrings') .
'</label></div>';
348 $submenu .=
'<div class="checkbox"><label for="checkLabels_noprefix">' .
BackendUtility::getFuncCheck(0,
'SET[labels_noprefix]', $this->MOD_SETTINGS[
'labels_noprefix'],
'',
'',
'id="checkLabels_noprefix"') . $lang->getLL(
'dontUseOrigValues') .
'</label></div>';
349 $submenu .=
'<div class="checkbox"><label for="checkOptions_sortlabel">' .
BackendUtility::getFuncCheck(0,
'SET[options_sortlabel]', $this->MOD_SETTINGS[
'options_sortlabel'],
'',
'',
'id="checkOptions_sortlabel"') . $lang->getLL(
'sortOptions') .
'</label></div>';
350 $submenu .=
'<div class="checkbox"><label for="checkShow_deleted">' .
BackendUtility::getFuncCheck(0,
'SET[show_deleted]', $this->MOD_SETTINGS[
'show_deleted'],
'',
'',
'id="checkShow_deleted"') . $lang->getLL(
'showDeleted') .
'</label></div>';
352 $this->view->assign(
'submenu', $submenu);
353 $this->view->assign(
'searchMode', $searchMode);
354 switch ($searchMode) {
357 $this->view->assign(
'queryMaker', $fullsearch->queryMaker());
361 $this->view->assign(
'searchOptions', $fullsearch->form());
362 $this->view->assign(
'results', $fullsearch->search());
372 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
378 'icon' => $this->iconFactory->getIconForRecord(
'pages', [],
Icon::SIZE_SMALL)->render(),
379 'count' => count($admin->getPageIdArray())
381 'translated_pages' => [
382 'icon' => $this->iconFactory->getIconForRecord(
'pages', [],
Icon::SIZE_SMALL)->render(),
383 'count' => count($admin->getPageTranslatedPageIDArray()),
386 'icon' => $this->iconFactory->getIconForRecord(
'pages', [
'hidden' => 1],
Icon::SIZE_SMALL)->render(),
387 'count' => $admin->getRecStats()[
'hidden'] ?? 0
390 'icon' => $this->iconFactory->getIconForRecord(
'pages', [
'deleted' => 1],
Icon::SIZE_SMALL)->render(),
391 'count' => isset($admin->getRecStats()[
'deleted'][
'pages']) ? count($admin->getRecStats()[
'deleted'][
'pages']) : 0
399 $doktype =
$GLOBALS[
'TCA'][
'pages'][
'columns'][
'doktype'][
'config'][
'items'];
400 if (is_array($doktype)) {
401 foreach ($doktype as $setup) {
402 if ($setup[1] !==
'--div--') {
404 'icon' => $this->iconFactory->getIconForRecord(
'pages', [
'doktype' => $setup[1]],
Icon::SIZE_SMALL)->render(),
405 'title' => $lang->sL($setup[0]) .
' (' . $setup[1] .
')',
406 'count' => (int)($admin->getRecStats()[
'doktype'][$setup[1]] ?? 0)
413 $id_list =
'-1,0,' . implode(
',', array_keys($admin->getPageIdArray()));
414 $id_list = rtrim($id_list,
',');
415 $admin->lostRecords($id_list);
416 if ($admin->fixLostRecord(GeneralUtility::_GET(
'fixLostRecords_table'), GeneralUtility::_GET(
'fixLostRecords_uid'))) {
417 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
419 $id_list =
'-1,0,' . implode(
',', array_keys($admin->getPageIdArray()));
420 $id_list = rtrim($id_list,
',');
421 $admin->lostRecords($id_list);
423 $tableStatistic = [];
424 $countArr = $admin->countRecords($id_list);
426 foreach (
$GLOBALS[
'TCA'] as $t => $value) {
427 if (
$GLOBALS[
'TCA'][$t][
'ctrl'][
'hideTable']) {
430 if ($t ===
'pages' && $admin->getLostPagesList() !==
'') {
431 $lostRecordCount = count(explode(
',', $admin->getLostPagesList()));
433 $lostRecordCount = isset($admin->getLRecords()[$t]) ? count($admin->getLRecords()[$t]) : 0;
435 if ($countArr[
'all'][$t]) {
436 $theNumberOfRe = (int)$countArr[
'non_deleted'][$t] .
'/' . $lostRecordCount;
442 $uriBuilder = GeneralUtility::makeInstance(\
TYPO3\CMS\Backend\Routing\UriBuilder::class);
443 if (is_array($admin->getLRecords()[$t])) {
444 foreach ($admin->getLRecords()[$t] as $data) {
445 if (!GeneralUtility::inList($admin->getLostPagesList(), $data[
'pid'])) {
446 $lr .=
'<div class="record"><a href="' . htmlspecialchars((
string)$uriBuilder->buildUriFromRoute(
'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>';
448 $lr .=
'<div class="record-noicon">uid:' . $data[
'uid'] .
', pid:' . $data[
'pid'] .
', ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(strip_tags($data[
'title']), 20)) .
'</div>';
452 $tableStatistic[$t] = [
453 'icon' => $this->iconFactory->getIconForRecord($t, [],
Icon::SIZE_SMALL)->render(),
454 'title' => $lang->sL(
$GLOBALS[
'TCA'][$t][
'ctrl'][
'title']),
455 'count' => $theNumberOfRe,
461 $this->view->assignMultiple([
462 'pages' => $pageStatistic,
463 'doktypes' => $doktypes,
464 'tables' => $tableStatistic
473 $admin = GeneralUtility::makeInstance(DatabaseIntegrityCheck::class);
474 $fkey_arrays = $admin->getGroupFields(
'');
475 $admin->selectNonEmptyRecordsWithFkeys($fkey_arrays);
476 $fileTest = $admin->testFileRefs();
478 if (is_array($fileTest[
'noFile'])) {
479 ksort($fileTest[
'noFile']);
481 $this->view->assignMultiple([
482 'files' => $fileTest,
483 'select_db' => $admin->testDBRefs($admin->getCheckSelectDBRefs()),
484 'group_db' => $admin->testDBRefs($admin->getCheckGroupDBRefs())
502 return GeneralUtility::makeInstance(PageRenderer::class);