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