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