[BUGFIX] Handle settings for report / check in linkvalidator
[Packages/TYPO3.CMS.git] / typo3 / sysext / linkvalidator / Classes / Report / LinkValidatorReport.php
index 56890b3..c2753db 100644 (file)
@@ -14,15 +14,18 @@ namespace TYPO3\CMS\Linkvalidator\Report;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\Driver\Statement;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\Connection;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
 
@@ -41,7 +44,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      *
      * @var array
      */
-    protected $pageRecord = array();
+    protected $pageRecord = [];
 
     /**
      * Information, if the module is accessible for the current user or not
@@ -52,10 +55,11 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
 
     /**
      * Depth for the recursive traversal of pages for the link validation
+     * For "Report" and "Check link" tab.
      *
-     * @var int
+     * @var array
      */
-    protected $searchLevel;
+    protected $searchLevel = ['report' => 0, 'check' => 0];
 
     /**
      * Link validation class
@@ -69,14 +73,14 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      *
      * @var array
      */
-    protected $modTS = array();
+    protected $modTS = [];
 
     /**
      * List of available link types to check defined in the TSconfig
      *
      * @var array
      */
-    protected $availableOptions = array();
+    protected $availableOptions = [];
 
     /**
      * List of link types currently chosen in the statistics table
@@ -84,23 +88,15 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      *
      * @var array
      */
-    protected $checkOpt = array();
-
-    /**
-     * Html for the statistics table with the checkboxes of the link types
-     * and the numbers of broken links for report tab
-     *
-     * @var string
-     */
-    protected $checkOptionsHtml;
+    protected $checkOpt = [];
 
     /**
      * Html for the statistics table with the checkboxes of the link types
-     * and the numbers of broken links for check links tab
+     * and the numbers of broken links for report / check links tab
      *
-     * @var string
+     * @var array
      */
-    protected $checkOptionsHtmlCheck;
+    protected $checkOptionsHtml = [];
 
     /**
      * Complete content (html) to be displayed
@@ -112,7 +108,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     /**
      * @var \TYPO3\CMS\Linkvalidator\Linktype\LinktypeInterface[]
      */
-    protected $hookObjectsArr = array();
+    protected $hookObjectsArr = [];
 
     /**
      * @var string
@@ -143,57 +139,65 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     {
         $this->getLanguageService()->includeLLFile('EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf');
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-        $this->searchLevel = GeneralUtility::_GP('search_levels');
+        $update = GeneralUtility::_GP('updateLinkList');
+        $prefix = 'check';
+        $other = 'report';
+
+        if (empty($update)) {
+            $prefix = 'report';
+            $other = 'check';
+        }
+
+        $this->searchLevel[$prefix] = GeneralUtility::_GP($prefix . '_search_levels');
         if (isset($this->pObj->id)) {
             $this->modTS = BackendUtility::getModTSconfig($this->pObj->id, 'mod.linkvalidator');
             $this->modTS = $this->modTS['properties'];
         }
-        $update = GeneralUtility::_GP('updateLinkList');
-        $prefix = '';
-        if (!empty($update)) {
-            $prefix = 'check';
-        }
-        $set = GeneralUtility::_GP($prefix . 'SET');
+        $set = GeneralUtility::_GP($prefix . '_SET');
         $this->pObj->handleExternalFunctionValue();
-        if (isset($this->searchLevel)) {
-            $this->pObj->MOD_SETTINGS['searchlevel'] = $this->searchLevel;
+        if (isset($this->searchLevel[$prefix])) {
+            $this->pObj->MOD_SETTINGS[$prefix . '_searchlevel'] = $this->searchLevel[$prefix];
         } else {
-            $this->searchLevel = $this->pObj->MOD_SETTINGS['searchlevel'];
+            $this->searchLevel[$prefix] = $this->pObj->MOD_SETTINGS[$prefix . '_searchlevel'];
         }
-        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
-            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $linkType => $value) {
-                // Compile list of all available types. Used for checking with button "Check Links".
-                if (strpos($this->modTS['linktypes'], $linkType) !== false) {
-                    $this->availableOptions[$linkType] = 1;
-                }
-                // Compile list of types currently selected by the checkboxes
-                if ($this->pObj->MOD_SETTINGS[$linkType] && empty($set) || $set[$linkType]) {
-                    $this->checkOpt[$linkType] = 1;
-                    $this->pObj->MOD_SETTINGS[$linkType] = 1;
-                } else {
-                    $this->pObj->MOD_SETTINGS[$linkType] = 0;
-                    unset($this->checkOpt[$linkType]);
-                }
+        if (isset($this->pObj->MOD_SETTINGS[$other . '_searchlevel'])) {
+            $this->searchLevel[$other] = $this->pObj->MOD_SETTINGS[$other . '_searchlevel'];
+        }
+        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] ?? [] as $linkType => $value) {
+            // Compile list of all available types. Used for checking with button "Check Links".
+            if (strpos($this->modTS['linktypes'], $linkType) !== false) {
+                $this->availableOptions[$linkType] = 1;
+            }
+            // Compile list of types currently selected by the checkboxes
+            if ($this->pObj->MOD_SETTINGS[$prefix . '_' . $linkType] && empty($set) || $set[$linkType]) {
+                $this->checkOpt[$prefix][$linkType] = 1;
+                $this->pObj->MOD_SETTINGS[$prefix . '_' . $linkType] = 1;
+            } else {
+                $this->pObj->MOD_SETTINGS[$prefix . '_' . $linkType] = 0;
+                unset($this->checkOpt[$prefix][$linkType]);
+            }
+            if (isset($this->pObj->MOD_SETTINGS[$other . '_' . $linkType])) {
+                $this->checkOpt[$other][$linkType] = $this->pObj->MOD_SETTINGS[$other . '_' . $linkType];
+            } else {
+                $this->checkOpt[$other][$linkType] = 0;
             }
         }
         $this->getBackendUser()->pushModuleData('web_info', $this->pObj->MOD_SETTINGS);
         $this->initialize();
 
         // Localization
-        $this->getPageRenderer()->addInlineLanguageLabelFile(
-            ExtensionManagementUtility::extPath('linkvalidator', 'Resources/Private/Language/Module/locallang.xlf')
-        );
+        $this->getPageRenderer()->addInlineLanguageLabelFile('EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf');
 
         if ($this->modTS['showCheckLinkTab'] == 1) {
-            $this->updateListHtml = '<input class="btn btn-default" type="submit" name="updateLinkList" id="updateLinkList" value="' . $this->getLanguageService()->getLL('label_update') . '"/>';
+            $this->updateListHtml = '<input class="btn btn-default t3js-update-button" type="submit" name="updateLinkList" id="updateLinkList" value="' . htmlspecialchars($this->getLanguageService()->getLL('label_update')) . '" data-notification-message="' . htmlspecialchars($this->getLanguageService()->getLL('label_update-link-list')) . '"/>';
         }
-        $this->refreshListHtml = '<input class="btn btn-default" type="submit" name="refreshLinkList" id="refreshLinkList" value="' . $this->getLanguageService()->getLL('label_refresh') . '"/>';
+        $this->refreshListHtml = '<input class="btn btn-default t3js-update-button" type="submit" name="refreshLinkList" id="refreshLinkList" value="' . htmlspecialchars($this->getLanguageService()->getLL('label_refresh')) . '" data-notification-message="' . htmlspecialchars($this->getLanguageService()->getLL('label_refresh-link-list')) . '"/>';
         $this->linkAnalyzer = GeneralUtility::makeInstance(LinkAnalyzer::class);
         $this->updateBrokenLinks();
 
         $brokenLinkOverView = $this->linkAnalyzer->getLinkCounts($this->pObj->id);
-        $this->checkOptionsHtml = $this->getCheckOptions($brokenLinkOverView);
-        $this->checkOptionsHtmlCheck = $this->getCheckOptions($brokenLinkOverView, 'check');
+        $this->checkOptionsHtml['report'] = $this->getCheckOptions($brokenLinkOverView, 'report');
+        $this->checkOptionsHtml['check'] = $this->getCheckOptions($brokenLinkOverView, 'check');
         $this->render();
 
         $pageTile = '';
@@ -212,48 +216,42 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      */
     protected function createTabs()
     {
-        $menuItems = array(
-            0 => array(
+        $menuItems = [
+            0 => [
                 'label' => $this->getLanguageService()->getLL('Report'),
                 'content' => $this->flush(true)
-            ),
-        );
+            ],
+        ];
 
         if ((bool)$this->modTS['showCheckLinkTab']) {
-            $menuItems[1] = array(
+            $menuItems[1] = [
                 'label' => $this->getLanguageService()->getLL('CheckLink'),
                 'content' => $this->flush()
-            );
+            ];
         }
 
-        // @todo: Use $this-moduleTemplate as soon as this class extends from AbstractModule
-        /** @var ModuleTemplate $moduleTemplate */
         $moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
         return $moduleTemplate->getDynamicTabMenu($menuItems, 'report-linkvalidator');
     }
 
     /**
      * Initializes the Module
-     *
-     * @return void
      */
     protected function initialize()
     {
-        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
-            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $linkType => $classRef) {
-                $this->hookObjectsArr[$linkType] = GeneralUtility::getUserObj($classRef);
-            }
+        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] ?? [] as $linkType => $className) {
+            $this->hookObjectsArr[$linkType] = GeneralUtility::makeInstance($className);
         }
 
         $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
         $this->doc->setModuleTemplate('EXT:linkvalidator/Resources/Private/Templates/mod_template.html');
 
-        $this->pageRecord = BackendUtility::readPageAccess($this->pObj->id, $this->getBackendUser()->getPagePermsClause(1));
+        $this->pageRecord = BackendUtility::readPageAccess($this->pObj->id, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
         if ($this->pObj->id && is_array($this->pageRecord) || !$this->pObj->id && $this->isCurrentUserAdmin()) {
             $this->isAccessibleForCurrentUser = true;
         }
 
-        $this->doc->addStyleSheet('module', ExtensionManagementUtility::extRelPath('linkvalidator') . 'Resources/Public/Css/styles.css');
+        $this->getPageRenderer()->addCssFile('EXT:linkvalidator/Resources/Public/Css/linkvalidator.css', 'stylesheet', 'screen');
         $this->getPageRenderer()->loadJquery();
         $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Linkvalidator/Linkvalidator');
 
@@ -267,12 +265,10 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
 
     /**
      * Updates the table of stored broken links
-     *
-     * @return void
      */
     protected function updateBrokenLinks()
     {
-        $searchFields = array();
+        $searchFields = [];
         // Get the searchFields from TypoScript
         foreach ($this->modTS['searchFields.'] as $table => $fieldList) {
             $fields = GeneralUtility::trimExplode(',', $fieldList, true);
@@ -287,9 +283,9 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
             // Get children pages
             $pageList = $this->linkAnalyzer->extGetTreeList(
                 $this->pObj->id,
-                $this->searchLevel,
+                $this->searchLevel['check'],
                 0,
-                $this->getBackendUser()->getPagePermsClause(1),
+                $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW),
                 $this->modTS['checkhidden']
             );
             if ($this->pObj->pageinfo['hidden'] == 0 || $this->modTS['checkhidden']) {
@@ -301,15 +297,13 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
             // Check if button press
             $update = GeneralUtility::_GP('updateLinkList');
             if (!empty($update)) {
-                $this->linkAnalyzer->getLinkStatistics($this->checkOpt, $this->modTS['checkhidden']);
+                $this->linkAnalyzer->getLinkStatistics($this->checkOpt['check'], $this->modTS['checkhidden']);
             }
         }
     }
 
     /**
      * Renders the content of the module
-     *
-     * @return void
      */
     protected function render()
     {
@@ -350,24 +344,26 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     /**
      * Builds the selector for the level of pages to search
      *
+     * @param string $prefix Indicating if the selector is build for the "report" or "check" tab
+     *
      * @return string Html code of that selector
      */
-    protected function getLevelSelector()
+    protected function getLevelSelector($prefix = 'report')
     {
         // Build level selector
-        $options = array();
-        $availableOptions = array(
-            0 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
-            1 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
-            2 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
-            3 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
-            4 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_4'),
-            999 => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
-        );
+        $options = [];
+        $availableOptions = [
+            0 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
+            1 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
+            2 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
+            3 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
+            4 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
+            999 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi')
+        ];
         foreach ($availableOptions as $optionValue => $optionLabel) {
-            $options[] = '<option value="' . $optionValue . '"' . ($optionValue === (int)$this->searchLevel ? ' selected="selected"' : '') . '>' . htmlspecialchars($optionLabel) . '</option>';
+            $options[] = '<option value="' . $optionValue . '"' . ($optionValue === (int)$this->searchLevel[$prefix] ? ' selected="selected"' : '') . '>' . htmlspecialchars($optionLabel) . '</option>';
         }
-        return '<select name="search_levels" class="form-control">' . implode('', $options) . '</select>';
+        return '<select name="' . $prefix . '_search_levels" class="form-control">' . implode('', $options) . '</select>';
     }
 
     /**
@@ -378,10 +374,14 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     protected function renderBrokenLinksTable()
     {
         $brokenLinkItems = '';
-        $brokenLinksTemplate = $this->templateService->getSubpart($this->doc->moduleTemplate, '###NOBROKENLINKS_CONTENT###');
-        $keyOpt = array();
-        if (is_array($this->checkOpt)) {
-            $keyOpt = array_keys($this->checkOpt);
+        $brokenLinksTemplate = $this->templateService->getSubpart(
+            $this->doc->moduleTemplate,
+            '###NOBROKENLINKS_CONTENT###'
+        );
+
+        $linkTypes = [];
+        if (is_array($this->checkOpt['report'])) {
+            $linkTypes = array_keys($this->checkOpt['report']);
         }
 
         // Table header
@@ -389,32 +389,24 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
 
         $rootLineHidden = $this->linkAnalyzer->getRootLineIsHidden($this->pObj->pageinfo);
         if (!$rootLineHidden || (bool)$this->modTS['checkhidden']) {
-            $pageList = $this->linkAnalyzer->extGetTreeList(
-                $this->pObj->id,
-                $this->searchLevel,
-                0,
-                $this->getBackendUser()->getPagePermsClause(1),
-                $this->modTS['checkhidden']
-            );
-            // Always add the current page, because we are just displaying the results
-            $pageList .= $this->pObj->id;
-
-            $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
-                '*',
-                'tx_linkvalidator_link',
-                'record_pid IN (' . $pageList . ') AND link_type IN (\'' . implode('\',\'', $keyOpt) . '\')',
-                '',
-                'record_uid ASC, uid ASC'
-            );
-            if (!empty($records)) {
+            $pageList = $this->getPageList($this->pObj->id);
+            $result = $this->getLinkValidatorBrokenLinks($pageList, $linkTypes);
+
+            if ($result->rowCount()) {
                 // Display table with broken links
-                $brokenLinksTemplate = $this->templateService->getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_CONTENT###');
-                $brokenLinksItemTemplate = $this->templateService->getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_ITEM###');
+                $brokenLinksTemplate = $this->templateService->getSubpart(
+                    $this->doc->moduleTemplate,
+                    '###BROKENLINKS_CONTENT###'
+                );
+                $brokenLinksItemTemplate = $this->templateService->getSubpart(
+                    $this->doc->moduleTemplate,
+                    '###BROKENLINKS_ITEM###'
+                );
 
                 // Table rows containing the broken links
-                $items = array();
-                foreach ($records as $record) {
-                    $items[] = $this->renderTableRow($record['table_name'], $record, $brokenLinksItemTemplate);
+                $items = [];
+                while ($row = $result->fetch()) {
+                    $items[] = $this->renderTableRow($row['table_name'], $row, $brokenLinksItemTemplate);
                 }
                 $brokenLinkItems = implode(LF, $items);
             } else {
@@ -423,15 +415,75 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         } else {
             $brokenLinksMarker = $this->getNoBrokenLinkMessage($brokenLinksMarker);
         }
+
         $brokenLinksTemplate = $this->templateService->substituteMarkerArray(
             $brokenLinksTemplate,
-            $brokenLinksMarker, '###|###',
+            $brokenLinksMarker,
+            '###|###',
             true
         );
+
         return $this->templateService->substituteSubpart($brokenLinksTemplate, '###BROKENLINKS_ITEM', $brokenLinkItems);
     }
 
     /**
+     * Generates an array of page uids from current pageUid.
+     * List does include pageUid itself.
+     *
+     * @param int $currentPageUid
+     * @return array
+     */
+    protected function getPageList(int $currentPageUid): array
+    {
+        $pageList = $this->linkAnalyzer->extGetTreeList(
+            $currentPageUid,
+            $this->searchLevel['report'],
+            0,
+            $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW),
+            $this->modTS['checkhidden']
+        );
+        // Always add the current page, because we are just displaying the results
+        $pageList .= $currentPageUid;
+
+        return GeneralUtility::intExplode(',', $pageList, true);
+    }
+
+    /**
+     * Prepare database query with pageList and keyOpt data.
+     *
+     * @param int[] $pageList Pages to check for broken links
+     * @param string[] $linkTypes Link types to validate
+     * @return Statement
+     */
+    protected function getLinkValidatorBrokenLinks(array $pageList, array $linkTypes): Statement
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable('tx_linkvalidator_link');
+        $queryBuilder
+            ->select('*')
+            ->from('tx_linkvalidator_link')
+            ->where(
+                $queryBuilder->expr()->in(
+                    'record_pid',
+                    $queryBuilder->createNamedParameter($pageList, Connection::PARAM_INT_ARRAY)
+                )
+            )
+            ->orderBy('record_uid')
+            ->addOrderBy('uid');
+
+        if (!empty($linkTypes)) {
+            $queryBuilder->andWhere(
+                $queryBuilder->expr()->in(
+                    'link_type',
+                    $queryBuilder->createNamedParameter($linkTypes, Connection::PARAM_STR_ARRAY)
+                )
+            );
+        }
+
+        return $queryBuilder->execute();
+    }
+
+    /**
      * Replace $brokenLinksMarker['NO_BROKEN_LINKS] with localized flashmessage
      *
      * @param array $brokenLinksMarker
@@ -439,7 +491,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      */
     protected function getNoBrokenLinkMessage(array $brokenLinksMarker)
     {
-        $brokenLinksMarker['LIST_HEADER'] = '<h3>' . $this->getLanguageService()->getLL('list.header', true) . '</h3>';
+        $brokenLinksMarker['LIST_HEADER'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('list.header')) . '</h3>';
         /** @var $message FlashMessage */
         $message = GeneralUtility::makeInstance(
             FlashMessage::class,
@@ -464,21 +516,21 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     protected function startTable()
     {
         // Listing head
-        $makerTableHead = array(
+        $makerTableHead = [
             'tablehead_path' => $this->getLanguageService()->getLL('list.tableHead.path'),
             'tablehead_element' => $this->getLanguageService()->getLL('list.tableHead.element'),
             'tablehead_headlink' => $this->getLanguageService()->getLL('list.tableHead.headlink'),
             'tablehead_linktarget' => $this->getLanguageService()->getLL('list.tableHead.linktarget'),
             'tablehead_linkmessage' => $this->getLanguageService()->getLL('list.tableHead.linkmessage'),
             'tablehead_lastcheck' => $this->getLanguageService()->getLL('list.tableHead.lastCheck'),
-        );
+        ];
 
         // Add CSH to the header of each column
         foreach ($makerTableHead as $column => $label) {
             $makerTableHead[$column] = BackendUtility::wrapInHelp('linkvalidator', $column, $label);
         }
         // Add section header
-        $makerTableHead['list_header'] = '<h3>' . $this->getLanguageService()->getLL('list.header', true) . '</h3>';
+        $makerTableHead['list_header'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('list.header')) . '</h3>';
         return $makerTableHead;
     }
 
@@ -492,7 +544,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      */
     protected function renderTableRow($table, array $row, $brokenLinksItemTemplate)
     {
-        $markerArray = array();
+        $markerArray = [];
         $fieldName = '';
         // Restore the linktype object
         $hookObj = $this->hookObjectsArr[$row['link_type']];
@@ -500,8 +552,10 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         // Construct link to edit the content element
         $requestUri = GeneralUtility::getIndpEnv('REQUEST_URI') .
             '&id=' . $this->pObj->id .
-            '&search_levels=' . $this->searchLevel;
-        $url = BackendUtility::getModuleUrl('record_edit', [
+            '&search_levels=' . $this->searchLevel['report'];
+        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
+        $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
+        $url = (string)$uriBuilder->buildUriFromRoute('record_edit', [
             'edit' => [
                 $table => [
                     $row['record_uid'] => 'edit'
@@ -533,7 +587,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         $element .= ' ' . htmlspecialchars(sprintf($this->getLanguageService()->getLL('list.field'), $fieldName));
         $markerArray['actionlinkOpen'] = $actionLinkOpen;
         $markerArray['actionlinkClose'] = $actionLinkClose;
-        $markerArray['actionlinkIcon'] = $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render();
+        $markerArray['actionlinkIcon'] = $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render();
         $markerArray['path'] = BackendUtility::getRecordPath($row['record_pid'], '', 0, 0);
         $markerArray['element'] = $element;
         $markerArray['headlink'] = htmlspecialchars($row['link_title']);
@@ -544,7 +598,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         } else {
             $linkMessage = '<span class="error">'
                 . nl2br(
-                    // Encode for output
+                // Encode for output
                     htmlspecialchars(
                         $hookObj->getErrorMessage($response['errorParams']),
                         ENT_QUOTES,
@@ -573,7 +627,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      */
     protected function getCheckOptions(array $brokenLinkOverView, $prefix = '')
     {
-        $markerArray = array();
+        $markerArray = [];
         if (!empty($prefix)) {
             $additionalAttr = ' class="' . $prefix . '"';
         } else {
@@ -581,7 +635,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         }
         $checkOptionsTemplate = $this->templateService->getSubpart($this->doc->moduleTemplate, '###CHECKOPTIONS_SECTION###');
         $hookSectionTemplate = $this->templateService->getSubpart($checkOptionsTemplate, '###HOOK_SECTION###');
-        $markerArray['statistics_header'] = '<h3>' . $this->getLanguageService()->getLL('report.statistics.header', true) . '</h3>';
+        $markerArray['statistics_header'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('report.statistics.header')) . '</h3>';
         $markerArray['total_count_label'] = BackendUtility::wrapInHelp('linkvalidator', 'checkboxes', $this->getLanguageService()->getLL('overviews.nbtotal'));
         $markerArray['total_count'] = $brokenLinkOverView['brokenlinkCount'] ?: '0';
 
@@ -594,18 +648,22 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
             ) {
                 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $type => $value) {
                     if (in_array($type, $linktypes)) {
-                        $hookSectionMarker = array(
+                        $hookSectionMarker = [
                             'count' => $brokenLinkOverView[$type] ?: '0',
-                        );
+                        ];
 
                         $translation = $this->getLanguageService()->getLL('hooks.' . $type) ?: $type;
-                        $hookSectionMarker['option'] = '<input type="checkbox"' . $additionalAttr . ' id="' . $prefix . 'SET_' . $type . '" name="' . $prefix
-                            . 'SET[' . $type . ']" value="1"' . ($this->pObj->MOD_SETTINGS[$type] ? ' checked="checked"' : '') . '/>' . '<label for="'
-                            . $prefix . 'SET_' . $type . '">&nbsp;' . htmlspecialchars($translation) . '</label>';
+
+                        $hookSectionMarker['option'] = '<input type="checkbox"' . $additionalAttr
+                            . ' id="' . $prefix . '_SET_' . $type
+                            . '" name="' . $prefix . '_SET[' . $type . ']" value="1"'
+                            . ($this->pObj->MOD_SETTINGS[$prefix . '_' . $type] ? ' checked="checked"' : '') . '/>' . '<label for="'
+                            . $prefix . '_SET_' . $type . '">&nbsp;' . htmlspecialchars($translation) . '</label>';
 
                         $hookSectionContent .= $this->templateService->substituteMarkerArray(
                             $hookSectionTemplate,
-                            $hookSectionMarker, '###|###',
+                            $hookSectionMarker,
+                            '###|###',
                             true,
                             true
                         );
@@ -628,11 +686,11 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
      */
     protected function getDocHeaderButtons()
     {
-        return array(
+        return [
             'csh' => BackendUtility::cshItem('_MOD_web_func', ''),
             'shortcut' => $this->getShortcutButton(),
             'save' => ''
-        );
+        ];
     }
 
     /**
@@ -651,40 +709,42 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
 
     /**
      * Gets the filled markers that are used in the HTML template
+     * Reports tab
      *
      * @return array The filled marker array
      */
     protected function getTemplateMarkers()
     {
-        return array(
+        return [
             'FUNC_TITLE' => $this->getLanguageService()->getLL('report.func.title'),
             'CHECKOPTIONS_TITLE' => $this->getLanguageService()->getLL('report.statistics.header'),
-            'FUNC_MENU' => $this->getLevelSelector(),
+            'FUNC_MENU' => $this->getLevelSelector('report'),
             'CONTENT' => $this->content,
-            'CHECKOPTIONS' => $this->checkOptionsHtml,
+            'CHECKOPTIONS' => $this->checkOptionsHtml['report'],
             'ID' => '<input type="hidden" name="id" value="' . $this->pObj->id . '" />',
-            'REFRESH' => '<input type="submit" class="btn btn-default" name="refreshLinkList" id="refreshLinkList" value="' . $this->getLanguageService()->getLL('label_refresh') . '" />',
+            'REFRESH' => '<input type="submit" class="btn btn-default t3js-update-button" name="refreshLinkList" id="refreshLinkList" value="' . htmlspecialchars($this->getLanguageService()->getLL('label_refresh')) . '" data-notification-message="' . htmlspecialchars($this->getLanguageService()->getLL('label_refresh-link-list')) . '" />',
             'UPDATE' => '',
-        );
+        ];
     }
 
     /**
      * Gets the filled markers that are used in the HTML template
+     * Check Links tab
      *
      * @return array The filled marker array
      */
     protected function getTemplateMarkersCheck()
     {
-        return array(
+        return [
             'FUNC_TITLE' => $this->getLanguageService()->getLL('checklinks.func.title'),
             'CHECKOPTIONS_TITLE' => $this->getLanguageService()->getLL('checklinks.statistics.header'),
-            'FUNC_MENU' => $this->getLevelSelector(),
+            'FUNC_MENU' => $this->getLevelSelector('check'),
             'CONTENT' => '',
-            'CHECKOPTIONS' => $this->checkOptionsHtmlCheck,
+            'CHECKOPTIONS' => $this->checkOptionsHtml['check'],
             'ID' => '<input type="hidden" name="id" value="' . $this->pObj->id . '" />',
             'REFRESH' => '',
-            'UPDATE' => '<input type="submit" class="btn btn-default" name="updateLinkList" id="updateLinkList" value="' . $this->getLanguageService()->getLL('label_update') . '"/>',
-        );
+            'UPDATE' => '<input type="submit" class="btn btn-default t3js-update-button" name="updateLinkList" id="updateLinkList" value="' . htmlspecialchars($this->getLanguageService()->getLL('label_update')) . '" data-notification-message="' . htmlspecialchars($this->getLanguageService()->getLL('label_update-link-list')) . '"/>',
+        ];
     }
 
     /**
@@ -700,7 +760,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     /**
      * Returns LanguageService
      *
-     * @return \TYPO3\CMS\Lang\LanguageService
+     * @return \TYPO3\CMS\Core\Localization\LanguageService
      */
     protected function getLanguageService()
     {
@@ -716,12 +776,4 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
     {
         return $GLOBALS['BE_USER'];
     }
-
-    /**
-     * @return \TYPO3\CMS\Core\Database\DatabaseConnection
-     */
-    protected function getDatabaseConnection()
-    {
-        return $GLOBALS['TYPO3_DB'];
-    }
 }