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