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