[CLEANUP] Use Permission constants consistently
[Packages/TYPO3.CMS.git] / typo3 / sysext / linkvalidator / Classes / Report / LinkValidatorReport.php
1 <?php
2 namespace TYPO3\CMS\Linkvalidator\Report;
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 Doctrine\DBAL\Driver\Statement;
18 use TYPO3\CMS\Backend\Template\DocumentTemplate;
19 use TYPO3\CMS\Backend\Template\ModuleTemplate;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Database\Connection;
22 use TYPO3\CMS\Core\Database\ConnectionPool;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Messaging\FlashMessage;
26 use TYPO3\CMS\Core\Messaging\FlashMessageService;
27 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
28 use TYPO3\CMS\Core\Type\Bitmask\Permission;
29 use TYPO3\CMS\Core\Utility\GeneralUtility;
30 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
31
32 /**
33 * Module 'Linkvalidator' for the 'linkvalidator' extension
34 */
35 class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModule
36 {
37 /**
38 * @var DocumentTemplate
39 */
40 public $doc;
41
42 /**
43 * Information about the current page record
44 *
45 * @var array
46 */
47 protected $pageRecord = [];
48
49 /**
50 * Information, if the module is accessible for the current user or not
51 *
52 * @var bool
53 */
54 protected $isAccessibleForCurrentUser = false;
55
56 /**
57 * Depth for the recursive traversal of pages for the link validation
58 *
59 * @var int
60 */
61 protected $searchLevel;
62
63 /**
64 * Link validation class
65 *
66 * @var LinkAnalyzer
67 */
68 protected $linkAnalyzer;
69
70 /**
71 * TSconfig of the current module
72 *
73 * @var array
74 */
75 protected $modTS = [];
76
77 /**
78 * List of available link types to check defined in the TSconfig
79 *
80 * @var array
81 */
82 protected $availableOptions = [];
83
84 /**
85 * List of link types currently chosen in the statistics table
86 * Used to show broken links of these types only
87 *
88 * @var array
89 */
90 protected $checkOpt = [];
91
92 /**
93 * Html for the statistics table with the checkboxes of the link types
94 * and the numbers of broken links for report tab
95 *
96 * @var string
97 */
98 protected $checkOptionsHtml;
99
100 /**
101 * Html for the statistics table with the checkboxes of the link types
102 * and the numbers of broken links for check links tab
103 *
104 * @var string
105 */
106 protected $checkOptionsHtmlCheck;
107
108 /**
109 * Complete content (html) to be displayed
110 *
111 * @var string
112 */
113 protected $content;
114
115 /**
116 * @var \TYPO3\CMS\Linkvalidator\Linktype\LinktypeInterface[]
117 */
118 protected $hookObjectsArr = [];
119
120 /**
121 * @var string
122 */
123 protected $updateListHtml = '';
124
125 /**
126 * @var string
127 */
128 protected $refreshListHtml = '';
129
130 /**
131 * @var MarkerBasedTemplateService
132 */
133 protected $templateService;
134
135 /**
136 * @var IconFactory
137 */
138 protected $iconFactory;
139
140 /**
141 * Main method of modfuncreport
142 *
143 * @return string Module content
144 */
145 public function main()
146 {
147 $this->getLanguageService()->includeLLFile('EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf');
148 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
149 $this->searchLevel = GeneralUtility::_GP('search_levels');
150 if (isset($this->pObj->id)) {
151 $this->modTS = BackendUtility::getModTSconfig($this->pObj->id, 'mod.linkvalidator');
152 $this->modTS = $this->modTS['properties'];
153 }
154 $update = GeneralUtility::_GP('updateLinkList');
155 $prefix = '';
156 if (!empty($update)) {
157 $prefix = 'check';
158 }
159 $set = GeneralUtility::_GP($prefix . 'SET');
160 $this->pObj->handleExternalFunctionValue();
161 if (isset($this->searchLevel)) {
162 $this->pObj->MOD_SETTINGS['searchlevel'] = $this->searchLevel;
163 } else {
164 $this->searchLevel = $this->pObj->MOD_SETTINGS['searchlevel'];
165 }
166 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] ?? [] as $linkType => $value) {
167 // Compile list of all available types. Used for checking with button "Check Links".
168 if (strpos($this->modTS['linktypes'], $linkType) !== false) {
169 $this->availableOptions[$linkType] = 1;
170 }
171 // Compile list of types currently selected by the checkboxes
172 if ($this->pObj->MOD_SETTINGS[$linkType] && empty($set) || $set[$linkType]) {
173 $this->checkOpt[$linkType] = 1;
174 $this->pObj->MOD_SETTINGS[$linkType] = 1;
175 } else {
176 $this->pObj->MOD_SETTINGS[$linkType] = 0;
177 unset($this->checkOpt[$linkType]);
178 }
179 }
180 $this->getBackendUser()->pushModuleData('web_info', $this->pObj->MOD_SETTINGS);
181 $this->initialize();
182
183 // Localization
184 $this->getPageRenderer()->addInlineLanguageLabelFile('EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf');
185
186 if ($this->modTS['showCheckLinkTab'] == 1) {
187 $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')) . '"/>';
188 }
189 $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')) . '"/>';
190 $this->linkAnalyzer = GeneralUtility::makeInstance(LinkAnalyzer::class);
191 $this->updateBrokenLinks();
192
193 $brokenLinkOverView = $this->linkAnalyzer->getLinkCounts($this->pObj->id);
194 $this->checkOptionsHtml = $this->getCheckOptions($brokenLinkOverView);
195 $this->checkOptionsHtmlCheck = $this->getCheckOptions($brokenLinkOverView, 'check');
196 $this->render();
197
198 $pageTile = '';
199 if ($this->pObj->id) {
200 $pageRecord = BackendUtility::getRecord('pages', $this->pObj->id);
201 $pageTile = '<h1>' . htmlspecialchars(BackendUtility::getRecordTitle('pages', $pageRecord)) . '</h1>';
202 }
203
204 return '<div id="linkvalidator-modfuncreport">' . $pageTile . $this->createTabs() . '</div>';
205 }
206
207 /**
208 * Create tabs to split the report and the checkLink functions
209 *
210 * @return string
211 */
212 protected function createTabs()
213 {
214 $menuItems = [
215 0 => [
216 'label' => $this->getLanguageService()->getLL('Report'),
217 'content' => $this->flush(true)
218 ],
219 ];
220
221 if ((bool)$this->modTS['showCheckLinkTab']) {
222 $menuItems[1] = [
223 'label' => $this->getLanguageService()->getLL('CheckLink'),
224 'content' => $this->flush()
225 ];
226 }
227
228 $moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
229 return $moduleTemplate->getDynamicTabMenu($menuItems, 'report-linkvalidator');
230 }
231
232 /**
233 * Initializes the Module
234 */
235 protected function initialize()
236 {
237 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] ?? [] as $linkType => $className) {
238 $this->hookObjectsArr[$linkType] = GeneralUtility::makeInstance($className);
239 }
240
241 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
242 $this->doc->setModuleTemplate('EXT:linkvalidator/Resources/Private/Templates/mod_template.html');
243
244 $this->pageRecord = BackendUtility::readPageAccess($this->pObj->id, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
245 if ($this->pObj->id && is_array($this->pageRecord) || !$this->pObj->id && $this->isCurrentUserAdmin()) {
246 $this->isAccessibleForCurrentUser = true;
247 }
248
249 $this->getPageRenderer()->addCssFile('EXT:linkvalidator/Resources/Public/Css/linkvalidator.css', 'stylesheet', 'screen');
250 $this->getPageRenderer()->loadJquery();
251 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Linkvalidator/Linkvalidator');
252
253 $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
254
255 // Don't access in workspace
256 if ($this->getBackendUser()->workspace !== 0) {
257 $this->isAccessibleForCurrentUser = false;
258 }
259 }
260
261 /**
262 * Updates the table of stored broken links
263 */
264 protected function updateBrokenLinks()
265 {
266 $searchFields = [];
267 // Get the searchFields from TypoScript
268 foreach ($this->modTS['searchFields.'] as $table => $fieldList) {
269 $fields = GeneralUtility::trimExplode(',', $fieldList, true);
270 foreach ($fields as $field) {
271 if (!$searchFields || !is_array($searchFields[$table]) || array_search($field, $searchFields[$table]) === false) {
272 $searchFields[$table][] = $field;
273 }
274 }
275 }
276 $rootLineHidden = $this->linkAnalyzer->getRootLineIsHidden($this->pObj->pageinfo);
277 if (!$rootLineHidden || $this->modTS['checkhidden'] == 1) {
278 // Get children pages
279 $pageList = $this->linkAnalyzer->extGetTreeList(
280 $this->pObj->id,
281 $this->searchLevel,
282 0,
283 $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW),
284 $this->modTS['checkhidden']
285 );
286 if ($this->pObj->pageinfo['hidden'] == 0 || $this->modTS['checkhidden']) {
287 $pageList .= $this->pObj->id;
288 }
289
290 $this->linkAnalyzer->init($searchFields, $pageList, $this->modTS);
291
292 // Check if button press
293 $update = GeneralUtility::_GP('updateLinkList');
294 if (!empty($update)) {
295 $this->linkAnalyzer->getLinkStatistics($this->checkOpt, $this->modTS['checkhidden']);
296 }
297 }
298 }
299
300 /**
301 * Renders the content of the module
302 */
303 protected function render()
304 {
305 if ($this->isAccessibleForCurrentUser) {
306 $this->content = $this->renderBrokenLinksTable();
307 } else {
308 // If no access or if ID == zero
309 /** @var FlashMessage $message */
310 $message = GeneralUtility::makeInstance(
311 FlashMessage::class,
312 $this->getLanguageService()->getLL('no.access'),
313 $this->getLanguageService()->getLL('no.access.title'),
314 FlashMessage::ERROR
315 );
316 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
317 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
318 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
319 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
320 $defaultFlashMessageQueue->enqueue($message);
321 }
322 }
323
324 /**
325 * Flushes the rendered content to the browser
326 *
327 * @param bool $form
328 * @return string $content
329 */
330 protected function flush($form = false)
331 {
332 return $this->doc->moduleBody(
333 $this->pageRecord,
334 $this->getDocHeaderButtons(),
335 $form ? $this->getTemplateMarkers() : $this->getTemplateMarkersCheck()
336 );
337 }
338
339 /**
340 * Builds the selector for the level of pages to search
341 *
342 * @return string Html code of that selector
343 */
344 protected function getLevelSelector()
345 {
346 // Build level selector
347 $options = [];
348 $availableOptions = [
349 0 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
350 1 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
351 2 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
352 3 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
353 4 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
354 999 => $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi')
355 ];
356 foreach ($availableOptions as $optionValue => $optionLabel) {
357 $options[] = '<option value="' . $optionValue . '"' . ($optionValue === (int)$this->searchLevel ? ' selected="selected"' : '') . '>' . htmlspecialchars($optionLabel) . '</option>';
358 }
359 return '<select name="search_levels" class="form-control">' . implode('', $options) . '</select>';
360 }
361
362 /**
363 * Displays the table of broken links or a note if there were no broken links
364 *
365 * @return string Content of the table or of the note
366 */
367 protected function renderBrokenLinksTable()
368 {
369 $brokenLinkItems = '';
370 $brokenLinksTemplate = $this->templateService->getSubpart(
371 $this->doc->moduleTemplate,
372 '###NOBROKENLINKS_CONTENT###'
373 );
374
375 $linkTypes = [];
376 if (is_array($this->checkOpt)) {
377 $linkTypes = array_keys($this->checkOpt);
378 }
379
380 // Table header
381 $brokenLinksMarker = $this->startTable();
382
383 $rootLineHidden = $this->linkAnalyzer->getRootLineIsHidden($this->pObj->pageinfo);
384 if (!$rootLineHidden || (bool)$this->modTS['checkhidden']) {
385 $pageList = $this->getPageList($this->pObj->id);
386 $result = $this->getLinkValidatorBrokenLinks($pageList, $linkTypes);
387
388 if ($result->rowCount()) {
389 // Display table with broken links
390 $brokenLinksTemplate = $this->templateService->getSubpart(
391 $this->doc->moduleTemplate,
392 '###BROKENLINKS_CONTENT###'
393 );
394 $brokenLinksItemTemplate = $this->templateService->getSubpart(
395 $this->doc->moduleTemplate,
396 '###BROKENLINKS_ITEM###'
397 );
398
399 // Table rows containing the broken links
400 $items = [];
401 while ($row = $result->fetch()) {
402 $items[] = $this->renderTableRow($row['table_name'], $row, $brokenLinksItemTemplate);
403 }
404 $brokenLinkItems = implode(LF, $items);
405 } else {
406 $brokenLinksMarker = $this->getNoBrokenLinkMessage($brokenLinksMarker);
407 }
408 } else {
409 $brokenLinksMarker = $this->getNoBrokenLinkMessage($brokenLinksMarker);
410 }
411
412 $brokenLinksTemplate = $this->templateService->substituteMarkerArray(
413 $brokenLinksTemplate,
414 $brokenLinksMarker,
415 '###|###',
416 true
417 );
418
419 return $this->templateService->substituteSubpart($brokenLinksTemplate, '###BROKENLINKS_ITEM', $brokenLinkItems);
420 }
421
422 /**
423 * Generates an array of page uids from current pageUid.
424 * List does include pageUid itself.
425 *
426 * @param int $currentPageUid
427 * @return array
428 */
429 protected function getPageList(int $currentPageUid): array
430 {
431 $pageList = $this->linkAnalyzer->extGetTreeList(
432 $currentPageUid,
433 $this->searchLevel,
434 0,
435 $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW),
436 $this->modTS['checkhidden']
437 );
438 // Always add the current page, because we are just displaying the results
439 $pageList .= $currentPageUid;
440
441 return GeneralUtility::intExplode(',', $pageList, true);
442 }
443
444 /**
445 * Prepare database query with pageList and keyOpt data.
446 *
447 * @param int[] $pageList Pages to check for broken links
448 * @param string[] $linkTypes Link types to validate
449 * @return Statement
450 */
451 protected function getLinkValidatorBrokenLinks(array $pageList, array $linkTypes): Statement
452 {
453 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
454 ->getQueryBuilderForTable('tx_linkvalidator_link');
455 $queryBuilder
456 ->select('*')
457 ->from('tx_linkvalidator_link')
458 ->where(
459 $queryBuilder->expr()->in(
460 'record_pid',
461 $queryBuilder->createNamedParameter($pageList, Connection::PARAM_INT_ARRAY)
462 )
463 )
464 ->orderBy('record_uid')
465 ->addOrderBy('uid');
466
467 if (!empty($linkTypes)) {
468 $queryBuilder->andWhere(
469 $queryBuilder->expr()->in(
470 'link_type',
471 $queryBuilder->createNamedParameter($linkTypes, Connection::PARAM_STR_ARRAY)
472 )
473 );
474 }
475
476 return $queryBuilder->execute();
477 }
478
479 /**
480 * Replace $brokenLinksMarker['NO_BROKEN_LINKS] with localized flashmessage
481 *
482 * @param array $brokenLinksMarker
483 * @return array $brokenLinksMarker['NO_BROKEN_LINKS] replaced with flashmessage
484 */
485 protected function getNoBrokenLinkMessage(array $brokenLinksMarker)
486 {
487 $brokenLinksMarker['LIST_HEADER'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('list.header')) . '</h3>';
488 /** @var $message FlashMessage */
489 $message = GeneralUtility::makeInstance(
490 FlashMessage::class,
491 $this->getLanguageService()->getLL('list.no.broken.links'),
492 $this->getLanguageService()->getLL('list.no.broken.links.title'),
493 FlashMessage::OK
494 );
495 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
496 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
497 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
498 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
499 $defaultFlashMessageQueue->enqueue($message);
500 $brokenLinksMarker['NO_BROKEN_LINKS'] = $defaultFlashMessageQueue->renderFlashMessages();
501 return $brokenLinksMarker;
502 }
503
504 /**
505 * Displays the table header of the table with the broken links
506 *
507 * @return string Code of content
508 */
509 protected function startTable()
510 {
511 // Listing head
512 $makerTableHead = [
513 'tablehead_path' => $this->getLanguageService()->getLL('list.tableHead.path'),
514 'tablehead_element' => $this->getLanguageService()->getLL('list.tableHead.element'),
515 'tablehead_headlink' => $this->getLanguageService()->getLL('list.tableHead.headlink'),
516 'tablehead_linktarget' => $this->getLanguageService()->getLL('list.tableHead.linktarget'),
517 'tablehead_linkmessage' => $this->getLanguageService()->getLL('list.tableHead.linkmessage'),
518 'tablehead_lastcheck' => $this->getLanguageService()->getLL('list.tableHead.lastCheck'),
519 ];
520
521 // Add CSH to the header of each column
522 foreach ($makerTableHead as $column => $label) {
523 $makerTableHead[$column] = BackendUtility::wrapInHelp('linkvalidator', $column, $label);
524 }
525 // Add section header
526 $makerTableHead['list_header'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('list.header')) . '</h3>';
527 return $makerTableHead;
528 }
529
530 /**
531 * Displays one line of the broken links table
532 *
533 * @param string $table Name of database table
534 * @param array $row Record row to be processed
535 * @param array $brokenLinksItemTemplate Markup of the template to be used
536 * @return string HTML of the rendered row
537 */
538 protected function renderTableRow($table, array $row, $brokenLinksItemTemplate)
539 {
540 $markerArray = [];
541 $fieldName = '';
542 // Restore the linktype object
543 $hookObj = $this->hookObjectsArr[$row['link_type']];
544
545 // Construct link to edit the content element
546 $requestUri = GeneralUtility::getIndpEnv('REQUEST_URI') .
547 '&id=' . $this->pObj->id .
548 '&search_levels=' . $this->searchLevel;
549 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
550 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
551 $url = (string)$uriBuilder->buildUriFromRoute('record_edit', [
552 'edit' => [
553 $table => [
554 $row['record_uid'] => 'edit'
555 ]
556 ],
557 'returnUrl' => $requestUri
558 ]);
559 $actionLinkOpen = '<a href="' . htmlspecialchars($url);
560 $actionLinkOpen .= '" title="' . htmlspecialchars($this->getLanguageService()->getLL('list.edit')) . '">';
561 $actionLinkClose = '</a>';
562 $elementHeadline = $row['headline'];
563 // Get the language label for the field from TCA
564 if ($GLOBALS['TCA'][$table]['columns'][$row['field']]['label']) {
565 $fieldName = $this->getLanguageService()->sL($GLOBALS['TCA'][$table]['columns'][$row['field']]['label']);
566 // Crop colon from end if present
567 if (substr($fieldName, '-1', '1') === ':') {
568 $fieldName = substr($fieldName, '0', strlen($fieldName) - 1);
569 }
570 }
571 // Fallback, if there is no label
572 $fieldName = !empty($fieldName) ? $fieldName : $row['field'];
573 // column "Element"
574 $element = '<span title="' . htmlspecialchars($table . ':' . $row['record_uid']) . '">' . $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render() . '</span>';
575 if (empty($elementHeadline)) {
576 $element .= '<i>' . htmlspecialchars($this->getLanguageService()->getLL('list.no.headline')) . '</i>';
577 } else {
578 $element .= htmlspecialchars($elementHeadline);
579 }
580 $element .= ' ' . htmlspecialchars(sprintf($this->getLanguageService()->getLL('list.field'), $fieldName));
581 $markerArray['actionlinkOpen'] = $actionLinkOpen;
582 $markerArray['actionlinkClose'] = $actionLinkClose;
583 $markerArray['actionlinkIcon'] = $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render();
584 $markerArray['path'] = BackendUtility::getRecordPath($row['record_pid'], '', 0, 0);
585 $markerArray['element'] = $element;
586 $markerArray['headlink'] = htmlspecialchars($row['link_title']);
587 $markerArray['linktarget'] = htmlspecialchars($hookObj->getBrokenUrl($row));
588 $response = unserialize($row['url_response']);
589 if ($response['valid']) {
590 $linkMessage = '<span class="valid">' . htmlspecialchars($this->getLanguageService()->getLL('list.msg.ok')) . '</span>';
591 } else {
592 $linkMessage = '<span class="error">'
593 . nl2br(
594 // Encode for output
595 htmlspecialchars(
596 $hookObj->getErrorMessage($response['errorParams']),
597 ENT_QUOTES,
598 'UTF-8',
599 false
600 )
601 )
602 . '</span>';
603 }
604 $markerArray['linkmessage'] = $linkMessage;
605
606 $lastRunDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $row['last_check']);
607 $lastRunTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $row['last_check']);
608 $markerArray['lastcheck'] = htmlspecialchars(sprintf($this->getLanguageService()->getLL('list.msg.lastRun'), $lastRunDate, $lastRunTime));
609
610 // Return the table html code as string
611 return $this->templateService->substituteMarkerArray($brokenLinksItemTemplate, $markerArray, '###|###', true, true);
612 }
613
614 /**
615 * Builds the checkboxes out of the hooks array
616 *
617 * @param array $brokenLinkOverView Array of broken links information
618 * @param string $prefix
619 * @return string code content
620 */
621 protected function getCheckOptions(array $brokenLinkOverView, $prefix = '')
622 {
623 $markerArray = [];
624 if (!empty($prefix)) {
625 $additionalAttr = ' class="' . $prefix . '"';
626 } else {
627 $additionalAttr = ' class="refresh"';
628 }
629 $checkOptionsTemplate = $this->templateService->getSubpart($this->doc->moduleTemplate, '###CHECKOPTIONS_SECTION###');
630 $hookSectionTemplate = $this->templateService->getSubpart($checkOptionsTemplate, '###HOOK_SECTION###');
631 $markerArray['statistics_header'] = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('report.statistics.header')) . '</h3>';
632 $markerArray['total_count_label'] = BackendUtility::wrapInHelp('linkvalidator', 'checkboxes', $this->getLanguageService()->getLL('overviews.nbtotal'));
633 $markerArray['total_count'] = $brokenLinkOverView['brokenlinkCount'] ?: '0';
634
635 $linktypes = GeneralUtility::trimExplode(',', $this->modTS['linktypes'], true);
636 $hookSectionContent = '';
637 if (is_array($linktypes)) {
638 if (
639 !empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])
640 && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])
641 ) {
642 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $type => $value) {
643 if (in_array($type, $linktypes)) {
644 $hookSectionMarker = [
645 'count' => $brokenLinkOverView[$type] ?: '0',
646 ];
647
648 $translation = $this->getLanguageService()->getLL('hooks.' . $type) ?: $type;
649 $hookSectionMarker['option'] = '<input type="checkbox"' . $additionalAttr . ' id="' . $prefix . 'SET_' . $type . '" name="' . $prefix
650 . 'SET[' . $type . ']" value="1"' . ($this->pObj->MOD_SETTINGS[$type] ? ' checked="checked"' : '') . '/>' . '<label for="'
651 . $prefix . 'SET_' . $type . '">&nbsp;' . htmlspecialchars($translation) . '</label>';
652
653 $hookSectionContent .= $this->templateService->substituteMarkerArray(
654 $hookSectionTemplate,
655 $hookSectionMarker,
656 '###|###',
657 true,
658 true
659 );
660 }
661 }
662 }
663 }
664 $checkOptionsTemplate = $this->templateService->substituteSubpart(
665 $checkOptionsTemplate,
666 '###HOOK_SECTION###',
667 $hookSectionContent
668 );
669 return $this->templateService->substituteMarkerArray($checkOptionsTemplate, $markerArray, '###|###', true, true);
670 }
671
672 /**
673 * Gets the buttons that shall be rendered in the docHeader
674 *
675 * @return array Available buttons for the docHeader
676 */
677 protected function getDocHeaderButtons()
678 {
679 return [
680 'csh' => BackendUtility::cshItem('_MOD_web_func', ''),
681 'shortcut' => $this->getShortcutButton(),
682 'save' => ''
683 ];
684 }
685
686 /**
687 * Gets the button to set a new shortcut in the backend (if current user is allowed to).
688 *
689 * @return string HTML representation of the shortcut button
690 */
691 protected function getShortcutButton()
692 {
693 $result = '';
694 if ($this->getBackendUser()->mayMakeShortcut()) {
695 $result = $this->doc->makeShortcutIcon('', 'function', $this->pObj->MCONF['name']);
696 }
697 return $result;
698 }
699
700 /**
701 * Gets the filled markers that are used in the HTML template
702 *
703 * @return array The filled marker array
704 */
705 protected function getTemplateMarkers()
706 {
707 return [
708 'FUNC_TITLE' => $this->getLanguageService()->getLL('report.func.title'),
709 'CHECKOPTIONS_TITLE' => $this->getLanguageService()->getLL('report.statistics.header'),
710 'FUNC_MENU' => $this->getLevelSelector(),
711 'CONTENT' => $this->content,
712 'CHECKOPTIONS' => $this->checkOptionsHtml,
713 'ID' => '<input type="hidden" name="id" value="' . $this->pObj->id . '" />',
714 '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')) . '" />',
715 'UPDATE' => '',
716 ];
717 }
718
719 /**
720 * Gets the filled markers that are used in the HTML template
721 *
722 * @return array The filled marker array
723 */
724 protected function getTemplateMarkersCheck()
725 {
726 return [
727 'FUNC_TITLE' => $this->getLanguageService()->getLL('checklinks.func.title'),
728 'CHECKOPTIONS_TITLE' => $this->getLanguageService()->getLL('checklinks.statistics.header'),
729 'FUNC_MENU' => $this->getLevelSelector(),
730 'CONTENT' => '',
731 'CHECKOPTIONS' => $this->checkOptionsHtmlCheck,
732 'ID' => '<input type="hidden" name="id" value="' . $this->pObj->id . '" />',
733 'REFRESH' => '',
734 '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')) . '"/>',
735 ];
736 }
737
738 /**
739 * Determines whether the current user is an admin
740 *
741 * @return bool Whether the current user is admin
742 */
743 protected function isCurrentUserAdmin()
744 {
745 return $this->getBackendUser()->isAdmin();
746 }
747
748 /**
749 * Returns LanguageService
750 *
751 * @return \TYPO3\CMS\Core\Localization\LanguageService
752 */
753 protected function getLanguageService()
754 {
755 return $GLOBALS['LANG'];
756 }
757
758 /**
759 * Returns the current BE user.
760 *
761 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
762 */
763 protected function getBackendUser()
764 {
765 return $GLOBALS['BE_USER'];
766 }
767 }