Added feature #16420: Add link validator module (Thanks to Patrick Gaumond)
[Packages/TYPO3.CMS.git] / typo3 / sysext / linkvalidator / modfunc1 / class.tx_linkvalidator_modfunc1.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2005 - 2010 Michael Miousse (michael.miousse@infoglobe.ca)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Module 'Link Validator' for the 'linkvalidator' extension.
27 *
28 * @author Michael Miousse <michael.miousse@infoglobe.ca>
29 * @author Jochen Rieger <j.rieger@connecta.ag>
30 * @package TYPO3
31 * @subpackage linkvalidator
32 */
33 class tx_linkvalidator_modfunc1 extends t3lib_extobjbase {
34
35 /**
36 * @var template
37 */
38 public $doc;
39 protected $relativePath;
40 protected $pageRecord = array();
41 protected $isAccessibleForCurrentUser = FALSE;
42
43 /**
44 * Main method of modfunc1
45 *
46 * @return html Module content
47 */
48 public function main() {
49 $LANG->includeLLFile('EXT:linkvalidator/modfunc1/locallang.xml');
50
51 $this->search_level = t3lib_div::_GP('search_levels');
52
53 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
54 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $linkType => $value) {
55 if ($this->pObj->MOD_SETTINGS[$linkType]) {
56 $this->checkOpt[$linkType] = 1;
57 }
58 }
59 }
60
61 $this->initialize();
62
63 $this->modTS = t3lib_BEfunc::getModTSconfig($this->pObj->id, 'mod.linkvalidator');
64 $this->modTS = $this->modTS['properties'];
65 if ($this->modTS['showUpdateButton'] === 'true' || $this->modTS['showUpdateButton'] === 1) {
66 $this->updateListHtml = '<input type="submit" name="updateLinkList" value="' . $GLOBALS['LANG']->getLL('label_update') . '"/>';
67 }
68 $this->refreshListHtml = '<input type="submit" name="refreshLinkList" value="' . $GLOBALS['LANG']->getLL('label_refresh') . '"/>';
69 $processing = t3lib_div::makeInstance('tx_linkvalidator_processing');
70 $this->updateBrokenLinks($processing);
71
72 $brokenLinkOverView = $processing->getLinkCounts($this->pObj->id);
73 $this->checkOptHtml = $this->getCheckOptions($brokenLinkOverView);
74
75 $this->render();
76
77 return $this->flush();
78 } // end function main()
79
80 /**
81 * Initialize menu array internally
82 *
83 * @return Module menu
84 */
85 public function modMenu() {
86 $modMenu = array (
87 'checkAllLink' => 0,
88 );
89
90 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
91 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $linkType => $value) {
92 $modMenu[$linkType] = 1;
93 }
94 }
95
96 return $modMenu;
97 } // end function modMenu()
98
99
100 /**
101 * Initializes the Module
102 *
103 * @return void
104 */
105 public function initialize() {
106 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
107 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $linkType => $classRef) {
108 $this->hookObjectsArr[$linkType] = &t3lib_div::getUserObj($classRef);
109 }
110 }
111
112 $this->doc = t3lib_div::makeInstance('template');
113 $this->doc->setModuleTemplate(t3lib_extMgm::extPath('linkvalidator') . 'modfunc1/mod_template.html');
114 $this->doc->backPath = $GLOBALS['BACK_PATH'];
115
116 $this->relativePath = t3lib_extMgm::extRelPath('linkvalidator');
117 $this->pageRecord = t3lib_BEfunc::readPageAccess($this->pObj->id, $this->perms_clause);
118
119 $this->isAccessibleForCurrentUser = FALSE;
120 if ($this->pObj->id && is_array($this->pageRecord) || !$this->pObj->id && $this->isCurrentUserAdmin()) {
121 $this->isAccessibleForCurrentUser = TRUE;
122 }
123
124 $this->loadHeaderData();
125
126 // Don't access in workspace
127 if ($GLOBALS['BE_USER']->workspace !== 0) {
128 $this->isAccessibleForCurrentUser = FALSE;
129 }
130 } // end function initialize()
131
132
133 /**
134 * Update the table of stored broken links
135 *
136 * @param array Processing object
137 * @return void
138 */
139 public function updateBrokenLinks($processing) {
140 $searchFields = array();
141
142 // get the searchFields from TypoScript
143 foreach ($this->modTS['searchFields.'] as $table => $fieldList) {
144 $fields = t3lib_div::trimExplode(',', $fieldList);
145 foreach ($fields as $field) {
146 if (!$searchFields || !is_array($searchFields[$table]) || array_search($field, $searchFields[$table]) == FALSE) {
147 $searchFields[$table][] = $field;
148 }
149 }
150 }
151 // get children pages
152 $pageList = t3lib_tsfeBeUserAuth::extGetTreeList(
153 $this->pObj->id,
154 $this->search_level,
155 0,
156 $GLOBALS['BE_USER']->getPagePermsClause(1)
157 );
158
159 $pageList .= $this->pObj->id;
160
161 $processing->init($searchFields, $pageList);
162
163 // check if button press
164 $update = t3lib_div::_GP('updateLinkList');
165
166 if (!empty($update)) {
167 $processing->getLinkStatistics($this->checkOpt, $this->modTS['checkhidden']);
168 }
169 } // end function updateBrokenLinks()
170
171
172 /**
173 * Renders the content of the module.
174 *
175 * @return void
176 */
177 public function render() {
178 if ($this->isAccessibleForCurrentUser) {
179 $this->content = $this->drawBrokenLinksTable();
180 } else {
181 // If no access or if ID == zero
182 $this->content .= $this->doc->spacer(10);
183 }
184 } // end function render()
185
186
187 /**
188 * Flushes the rendered content to browser.
189 *
190 * @return void
191 */
192 public function flush() {
193 $content.= $this->doc->moduleBody(
194 $this->pageRecord,
195 $this->getDocHeaderButtons(),
196 $this->getTemplateMarkers()
197 );
198
199 return $content;
200 } // end function flush()
201
202 /**
203 * @return string
204 */
205 protected function getLevelSelector() {
206 // Make level selector:
207 $opt = array();
208 $parts = array(
209 0 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.depth_0'),
210 1 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.depth_1'),
211 2 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.depth_2'),
212 3 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.depth_3'),
213 999 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.depth_infi'),
214 );
215
216 foreach ($parts as $kv => $label) {
217 $opt[] = '<option value="' . $kv . '"' . ($kv == intval($this->search_level) ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
218 }
219 $lMenu = '<select name="search_levels">' . implode('', $opt) . '</select>';
220 return $lMenu;
221 }
222
223 /**
224 * Display the table of broken links
225 *
226 * @return html Content of the table
227 */
228 protected function drawBrokenLinksTable() {
229 $content = '';
230 $items = array();
231 $brokenLinkItems = '';
232 $keyOpt = array();
233
234 $brokenLinksTemplate = t3lib_parsehtml::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_CONTENT###');
235
236 // table header
237 $brokenLinksMarker = $this->startTable();
238 $brokenLinksTemplate = t3lib_parsehtml::substituteMarkerArray($brokenLinksTemplate, $brokenLinksMarker, '###|###', TRUE);
239
240 $brokenLinksItemTemplate = t3lib_parsehtml::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_ITEM###');
241 if (is_array($this->checkOpt)) {
242 $keyOpt = array_keys($this->checkOpt);
243 }
244
245 $pageList = t3lib_tsfeBeUserAuth::extGetTreeList(
246 $this->pObj->id,
247 $this->search_level,
248 0,
249 $GLOBALS['BE_USER']->getPagePermsClause(1)
250 );
251 $pageList .= $this->pObj->id;
252 if (($res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
253 '*',
254 'tx_linkvalidator_links',
255 'recpid in (' . $pageList . ') and typelinks in (\'' . implode("','", $keyOpt) . '\')')
256 )) {
257 // table rows containing the broken links
258 while (($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
259 $alter = $alter % 2 ? FALSE : TRUE;
260 $items[] = $this->drawTableRow($row['tablename'], $row, $alter, $brokenLinksItemTemplate);
261 }
262 }
263
264 if (is_array($items)) {
265 $brokenLinkItems = implode(chr(10), $items);
266 }
267
268 $content = t3lib_parsehtml::substituteSubpart($brokenLinksTemplate, '###BROKENLINKS_ITEM', $brokenLinkItems);
269
270 return $content;
271 } // end function drawBrokenLinksTable()
272
273
274 /**
275 * Calls t3lib_tsfeBeUserAuth::extGetTreeList.
276 * Although this duplicates the function t3lib_tsfeBeUserAuth::extGetTreeList
277 * this is necessary to create the object that is used recursively by the original function.
278 *
279 * Generates a list of Page-uid's from $id. List does not include $id itself
280 * The only pages excluded from the list are deleted pages.
281 *
282 * level in the tree to start collecting uid's. Zero means
283 * 'start right away', 1 = 'next level and out'
284 *
285 * @param integer Start page id
286 * @param integer Depth to traverse down the page tree.
287 * @param integer $begin is an optional integer that determines at which
288 * @param string Perms clause
289 * @return string Returns the list with a comma in the end (if any pages selected!)
290 */
291 public function extGetTreeList($id, $depth, $begin = 0, $perms_clause) {
292 return t3lib_tsfeBeUserAuth::extGetTreeList($id, $depth, $begin, $perms_clause);
293 }
294
295
296 /**
297 * Display table begin of the broken links
298 *
299 * @return html Code of content
300 */
301 protected function startTable() {
302 global $LANG;
303
304 // Listing head
305 $makerTableHead = array();
306 $makerTableHead['list_header'] = $this->doc->sectionHeader($LANG->getLL('list.header'), $h_func);
307 $makerTableHead['bgColor2'] = $this->doc->bgColor2;
308
309 $makerTableHead['tablehead_path'] = $LANG->getLL('list.tableHead.path');
310 $makerTableHead['tablehead_type'] = $LANG->getLL('list.tableHead.type');
311 $makerTableHead['tablehead_headline'] = $LANG->getLL('list.tableHead.headline');
312 $makerTableHead['tablehead_field'] = $LANG->getLL('list.tableHead.field');
313 $makerTableHead['tablehead_headlink'] = $LANG->getLL('list.tableHead.headlink');
314 $makerTableHead['tablehead_linktarget'] = $LANG->getLL('list.tableHead.linktarget');
315 $makerTableHead['tablehead_linkmessage'] = $LANG->getLL('list.tableHead.linkmessage');
316 $makerTableHead['tablehead_lastcheck'] = $LANG->getLL('list.tableHead.lastCheck');
317
318 return $makerTableHead;
319 } // end function startTable()
320
321
322 /**
323 * Display line of the broken links table
324 *
325 * @param string table
326 * @param string row record
327 * @param bool alternate color between rows
328 * @return html code of content
329 */
330 protected function drawTableRow($table, $row, $switch, $brokenLinksItemTemplate) {
331 $markerArray = array();
332 if (is_array($row) && !empty($row['typelinks'])) {
333 if (($hookObj = $this->hookObjectsArr[$row['typelinks']])) {
334 $brokenUrl = $hookObj->getBrokenUrl($row);
335 }
336 }
337
338 $params = '&edit[' . $table . '][' . $row['recuid'] . ']=edit';
339 $actionLinks = '<a href="#" onclick="' . t3lib_BEfunc::editOnClick($params, $GLOBALS['BACK_PATH'], '') . '">'.
340 t3lib_iconWorks::getSpriteIcon('actions-document-open') . '</a>';
341
342 $elementType = $row['headline'];
343 if (empty($elementType)) {
344 $elementType = $table . ':' . $row['recuid'];
345 }
346
347 //Alternating row colors
348 if ($switch == TRUE) {
349 $switch = FALSE;
350 $markerArray['bgcolor_alternating'] = $this->doc->bgColor3;
351 } elseif ($switch == FALSE) {
352 $switch = TRUE;
353 $markerArray['bgcolor_alternating'] = $this->doc->bgColor5;
354 }
355
356 $markerArray['actionlink'] = $actionLinks;
357 $markerArray['path'] = t3lib_BEfunc::getRecordPath($row['recpid'], '', 0, 0);
358 $markerArray['type'] = t3lib_iconWorks::getSpriteIconForRecord($table, $row, array('title' => $row['recuid']));
359 $markerArray['headline'] = $elementType;
360 $markerArray['field'] = $row['field'];
361 $markerArray['headlink'] = $row['linktitle'];
362 $markerArray['linktarget'] = $brokenUrl;
363 $markerArray['linkmessage'] = $row['urlresponse'];
364 $lastRunDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $row['lastcheck']);
365 $lastRunTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $row['lastcheck']);
366 $message = sprintf($GLOBALS['LANG']->getLL('list.msg.lastRun'), $lastRunDate, $lastRunTime);
367 $markerArray['lastcheck'] = $message;
368
369 // Return the table html code as string
370 return t3lib_parsehtml::substituteMarkerArray($brokenLinksItemTemplate, $markerArray, '###|###', TRUE, TRUE);
371 } // end function drawTableRow()
372
373
374 /**
375 * Builds the checkboxes out of the hooks array
376 *
377 * @param array array of broken links informations
378 * @return html code content
379 */
380 protected function getCheckOptions($brokenLinkOverView) {
381 global $LANG;
382 $content = '';
383 $checkOptionsTemplate = '';
384 $checkOptionsTemplate = t3lib_parsehtml::getSubpart($this->doc->moduleTemplate, '###CHECKOPTIONS_SECTION###');
385
386 $hookSectionContent = '';
387 $hookSectionTemplate = t3lib_parsehtml::getSubpart($checkOptionsTemplate, '###HOOK_SECTION###');
388
389 $markerArray['total_count_label'] = $LANG->getLL('overviews.nbtotal');
390 $markerArray['total_count'] = $brokenLinkOverView['brokenlinkCount'];
391
392 $linktypes = t3lib_div::trimExplode(',', $this->modTS['linktypes'], 1);
393 $hookSectionContent = '';
394
395 if (is_array($linktypes)) {
396 if (!empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])
397 && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])
398 ) {
399 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $key => $value) {
400 if (in_array($key, $linktypes)) {
401 $hookSectionMarker = array();
402 $hookSectionMarker['count'] = $brokenLinkOverView[$key];
403 $trans = $GLOBALS['LANG']->getLL('hooks.' . $key);
404 $trans = $trans ? $trans : $key;
405 $option = t3lib_BEfunc::getFuncCheck(
406 $this->pObj->id, 'SET[' . $key . ']',
407 $this->pObj->MOD_SETTINGS[$key]
408 ) . '<label for="' . $key . '">' . $trans . '</label>';
409 $hookSectionMarker['option'] = $option;
410 $hookSectionContent .= t3lib_parsehtml::substituteMarkerArray($hookSectionTemplate, $hookSectionMarker, '###|###', TRUE, TRUE);
411 }
412 }
413 }
414 }
415
416 $checkOptionsTemplate = t3lib_parsehtml::substituteSubpart($checkOptionsTemplate, '###HOOK_SECTION###', $hookSectionContent);
417
418 return t3lib_parsehtml::substituteMarkerArray($checkOptionsTemplate, $markerArray, '###|###', TRUE, TRUE);
419 } // end function getCheckOptions()
420
421
422 /**
423 * Loads data in the HTML head section (e.g. JavaScript or stylesheet information).
424 *
425 * @return void
426 */
427 protected function loadHeaderData() {
428 $this->doc->addStyleSheet('linkvalidator', $this->relativePath . 'res/linkvalidator.css', 'linkvalidator');
429 }
430
431
432 /**
433 * Gets the buttons that shall be rendered in the docHeader.
434 *
435 * @return array Available buttons for the docHeader
436 */
437 protected function getDocHeaderButtons() {
438 $buttons = array(
439 'csh' => t3lib_BEfunc::cshItem('_MOD_web_func', '', $GLOBALS['BACK_PATH']),
440 'shortcut' => $this->getShortcutButton(),
441 'save' => ''
442 );
443 return $buttons;
444 }
445
446
447 /**
448 * Gets the button to set a new shortcut in the backend (if current user is allowed to).
449 *
450 * @return string HTML representiation of the shortcut button
451 */
452 protected function getShortcutButton() {
453 $result = '';
454 if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
455 $result = $this->doc->makeShortcutIcon('', 'function', $this->MCONF['name']);
456 }
457 return $result;
458 }
459
460
461 /**
462 * Gets the filled markers that are used in the HTML template.
463 *
464 * @return array The filled marker array
465 */
466 protected function getTemplateMarkers() {
467 $markers = array(
468 'FUNC_MENU' => $this->getLevelSelector(),
469 'CONTENT' => $this->content,
470 'TITLE' => $GLOBALS['LANG']->getLL('title'),
471 'CHECKALLLINK' => $this->checkAllHtml,
472 'CHECKOPTIONS' => $this->checkOptHtml,
473 'ID' => '<input type="hidden" name="id" value="' . $this->pObj->id . '"/>',
474 'REFRESH' => $this->refreshListHtml,
475 'UPDATE' =>$this->updateListHtml
476 );
477
478 return $markers;
479 } // end function getTemplateMarkers()
480
481
482 /**
483 * Determines whether the current user is admin.
484 *
485 * @return boolean Whether the current user is admin
486 */
487 protected function isCurrentUserAdmin() {
488 return ((bool) $GLOBALS['BE_USER']->user['admin']);
489 }
490 } // end class
491
492 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/linkvalidator/modfunc1/class.tx_linkvalidator_modfunc1.php']) {
493 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/linkvalidator/modfunc1/class.tx_linkvalidator_modfunc1.php']);
494 }
495
496 ?>