[TASK] Cleanup ext:indexed_search web_info module routing
[Packages/TYPO3.CMS.git] / typo3 / sysext / indexed_search / Classes / Controller / IndexedPagesController.php
1 <?php
2 namespace TYPO3\CMS\IndexedSearch\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2001-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Backend\Utility\BackendUtility;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * Indexing class for TYPO3 frontend
32 *
33 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
34 */
35 class IndexedPagesController extends \TYPO3\CMS\Backend\Module\AbstractFunctionModule {
36
37 // Internal, dynamic:
38 /**
39 * @todo Define visibility
40 */
41 public $allPhashListed = array();
42
43 // phash values accumulations for link to clear all
44 /**
45 * @todo Define visibility
46 */
47 public $external_parsers = array();
48
49 // External content parsers - objects set here with file extensions as keys.
50 /**
51 * @todo Define visibility
52 */
53 public $iconFileNameCache = array();
54
55 // File extensions - icon map/cache.
56 /**
57 * @todo Define visibility
58 */
59 public $indexerConfig = array();
60
61 // Indexer configuration, coming from $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']
62 /**
63 * @todo Define visibility
64 */
65 public $enableMetaphoneSearch = FALSE;
66
67 /**
68 * Indexer object
69 *
70 * @var \TYPO3\CMS\IndexedSearch\Indexer
71 * @todo Define visibility
72 */
73 public $indexerObj;
74
75 /**
76 * @int Default number of list entries per page
77 */
78 protected $maxListPerPage;
79
80 /**
81 * Initialize menu array internally
82 *
83 * @return void
84 * @todo Define visibility
85 */
86 public function modMenu() {
87 global $LANG;
88 return array(
89 'depth' => array(
90 0 => $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
91 1 => $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
92 2 => $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
93 3 => $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
94 999 => $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
95 ),
96 'type' => array(
97 0 => 'Overview',
98 1 => 'Technical Details',
99 2 => 'Words and content'
100 )
101 );
102 }
103
104 /**
105 * Produces main content of the module
106 *
107 * @return string HTML output
108 * @todo Define visibility
109 */
110 public function main() {
111 // Initializes the module. Done in this function because we may need to re-initialize if data is submitted!
112 global $LANG, $TYPO3_CONF_VARS;
113 // Return if no page id:
114 if ($this->pObj->id <= 0) {
115 return;
116 }
117 // Indexer configuration from Extension Manager interface:
118 $this->indexerConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
119 // Workaround: If the extension configuration was not updated yet, the value is not existing
120 $this->enableMetaphoneSearch = isset($this->indexerConfig['enableMetaphoneSearch']) ? ($this->indexerConfig['enableMetaphoneSearch'] ? TRUE : FALSE) : TRUE;
121 // Initialize max-list items
122 $this->maxListPerPage = GeneralUtility::_GP('listALL') ? 100000 : 100;
123 // Processing deletion of phash rows:
124 if (GeneralUtility::_GP('deletePhash')) {
125 $this->removeIndexedPhashRow(GeneralUtility::_GP('deletePhash'));
126 }
127 // Processing stop-words:
128 if (GeneralUtility::_POST('_stopwords')) {
129 $this->processStopWords(GeneralUtility::_POST('stopWord'));
130 }
131 // Processing stop-words:
132 if (GeneralUtility::_POST('_pageKeywords')) {
133 $this->processPageKeywords(GeneralUtility::_POST('pageKeyword'), GeneralUtility::_POST('pageKeyword_pageUid'));
134 }
135 // Initialize external document parsers:
136 // Example configuration, see ext_localconf.php of this file!
137 if (is_array($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers'])) {
138 foreach ($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef) {
139 $this->external_parsers[$extension] = GeneralUtility::getUserObj($_objRef);
140 // Init parser and if it returns FALSE, unset its entry again:
141 if (!$this->external_parsers[$extension]->softInit($extension)) {
142 unset($this->external_parsers[$extension]);
143 }
144 }
145 }
146 // Initialize indexer if we need it (metaphone display does...)
147 $this->indexerObj = GeneralUtility::makeInstance('TYPO3\\CMS\\IndexedSearch\\Indexer');
148 // Set CSS styles specific for this document:
149 $this->pObj->content = str_replace('/*###POSTCSSMARKER###*/', '
150 TABLE.c-list TR TD { white-space: nowrap; vertical-align: top; }
151 ', $this->pObj->content);
152 // Check if details for a phash record should be shown:
153 if (GeneralUtility::_GET('phash')) {
154 // Show title / function menu:
155 $theOutput .= $this->pObj->doc->spacer(5);
156 $theOutput .= $this->pObj->doc->section('Details for a single result row:', $this->showDetailsForPhash(GeneralUtility::_GET('phash')), 0, 1);
157 } elseif (GeneralUtility::_GET('wid')) {
158 // Show title / function menu:
159 $theOutput .= $this->pObj->doc->spacer(5);
160 $theOutput .= $this->pObj->doc->section('Details for a word:', $this->showDetailsForWord(GeneralUtility::_GET('wid')), 0, 1);
161 } elseif ($this->enableMetaphoneSearch && GeneralUtility::_GET('metaphone')) {
162 // Show title / function menu:
163 $theOutput .= $this->pObj->doc->spacer(5);
164 $theOutput .= $this->pObj->doc->section('Details for metaphone value:', $this->showDetailsForMetaphone(GeneralUtility::_GET('metaphone')), 0, 1);
165 } elseif (GeneralUtility::_GET('reindex')) {
166 // Show title / function menu:
167 $theOutput .= $this->pObj->doc->spacer(5);
168 $theOutput .= $this->pObj->doc->section('Reindexing...', $this->reindexPhash(GeneralUtility::_GET('reindex'), GeneralUtility::_GET('reindex_id')), 0, 1);
169 } else {
170 // Detail listings:
171 // Depth function menu:
172 $h_func = BackendUtility::getFuncMenu($this->pObj->id, 'SET[type]', $this->pObj->MOD_SETTINGS['type'], $this->pObj->MOD_MENU['type']);
173 $h_func .= BackendUtility::getFuncMenu($this->pObj->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
174 // Show title / function menu:
175 $theOutput .= $this->pObj->doc->header($LANG->getLL('title'));
176 $theOutput .= $this->pObj->doc->section('', $h_func, 0, 1);
177 $theOutput .= $this->drawTableOfIndexedPages();
178 }
179 return $theOutput;
180 }
181
182 /*******************************
183 *
184 * Drawing table of indexed pages
185 *
186 ******************************/
187 /**
188 * Produces a table with indexing information for each page.
189 *
190 * @return string HTML output
191 * @todo Define visibility
192 */
193 public function drawTableOfIndexedPages() {
194 global $BACK_PATH;
195 // Drawing tree:
196 $tree = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Tree\\View\\PageTreeView');
197 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
198 $tree->init('AND ' . $perms_clause);
199 $HTML = '<img src="' . $BACK_PATH . \TYPO3\CMS\Backend\Utility\IconUtility::getIcon('pages', $this->pObj->pageinfo) . '" width="18" height="16" align="top" alt="" />';
200 $tree->tree[] = array(
201 'row' => $this->pObj->pageinfo,
202 'HTML' => $HTML
203 );
204 if ($this->pObj->MOD_SETTINGS['depth']) {
205 $tree->getTree($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'], '');
206 }
207 // Traverse page tree:
208 $code = '';
209 foreach ($tree->tree as $data) {
210 $code .= $this->indexed_info($data['row'], $data['HTML'] . $this->showPageDetails(
211 BackendUtility::getRecordTitlePrep($data['row']['title']), $data['row']['uid']));
212 }
213 if ($code) {
214 $code = '<br /><br />
215 <table border="0" cellspacing="1" cellpadding="2" class="c-list">' . $this->printPhashRowHeader() . $code . '</table>';
216 // Create section to output:
217 $theOutput .= $this->pObj->doc->section('', $code, 0, 1);
218 } else {
219 $theOutput .= $this->pObj->doc->section('', '<br /><br />' . $this->pObj->doc->icons(1) . 'There were no indexed pages found in the tree.<br /><br />', 0, 1);
220 }
221 return $theOutput;
222 }
223
224 /**
225 * Create information table row for a page regarding indexing information.
226 *
227 * @param array Data array for this page
228 * @param string HTML content for first column (page tree icon etc.)
229 * @return string HTML code. (table row)
230 * @todo Define visibility
231 */
232 public function indexed_info($data, $firstColContent) {
233 // Query:
234 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('ISEC.phash_t3, ISEC.rl0, ISEC.rl1, ISEC.rl2, ISEC.page_id, ISEC.uniqid, ' . 'IP.phash, IP.phash_grouping, IP.cHashParams, IP.data_filename, IP.data_page_id, ' . 'IP.data_page_reg1, IP.data_page_type, IP.data_page_mp, IP.gr_list, IP.item_type, ' . 'IP.item_title, IP.item_description, IP.item_mtime, IP.tstamp, IP.item_size, ' . 'IP.contentHash, IP.crdate, IP.parsetime, IP.sys_language_uid, IP.item_crdate, ' . 'IP.externalUrl, IP.recordUid, IP.freeIndexUid, IP.freeIndexSetId, count(*) AS count_val', 'index_phash IP, index_section ISEC', 'IP.phash = ISEC.phash AND ISEC.page_id = ' . (int)$data['uid'], 'IP.phash,IP.phash_grouping,IP.cHashParams,IP.data_filename,IP.data_page_id,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2,ISEC.page_id,ISEC.uniqid,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId', 'IP.item_type, IP.tstamp', $this->maxListPerPage + 1);
235 // Initialize variables:
236 $rowCount = 0;
237 $lines = array();
238 // Collecting HTML rows here.
239 $phashAcc = array();
240 // Collecting phash values (to remove local indexing for)
241 $phashAcc[] = 0;
242 // Traverse the result set of phash rows selected:
243 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
244 if ($rowCount == $this->maxListPerPage) {
245 $rowCount++;
246 // Increase to the extra warning row will appear as well.
247 break;
248 }
249 // Adds a display row:
250 $lines[$row['phash_grouping']][] = $this->printPhashRow($row, isset($lines[$row['phash_grouping']]), $this->getGrListEntriesForPhash($row['phash'], $row['gr_list']));
251 $rowCount++;
252 $phashAcc[] = $row['phash'];
253 $this->allPhashListed[] = $row['phash'];
254 }
255 // Compile rows into the table:
256 $out = '';
257 $cellAttrib = $data['_CSSCLASS'] ? ' class="' . $data['_CSSCLASS'] . '"' : '';
258 if (count($lines)) {
259 $firstColContent = '<td rowspan="' . $rowCount . '"' . $cellAttrib . '>' . $firstColContent . '</td>';
260 foreach ($lines as $rowSet) {
261 foreach ($rowSet as $rows) {
262 $out .= '
263 <tr class="bgColor-20">' . $firstColContent . implode('', $rows) . '</tr>';
264 $firstColContent = '';
265 }
266 }
267 if ($rowCount > $this->maxListPerPage) {
268 // Now checking greater than, because we increased $rowCount before...
269 $out .= '
270 <tr class="bgColor-20">
271 <td>&nbsp;</td>
272 <td colspan="' . ($this->returnNumberOfColumns() - 1) . '">' . $this->pObj->doc->icons(3) . '<span class="">There were more than ' . $this->maxListPerPage . ' rows. <a href="' . htmlspecialchars(('index.php?id=' . $this->pObj->id . '&listALL=1')) . '">Click here to list them ALL!</a></span></td>
273 </tr>';
274 }
275 } else {
276 $out .= '
277 <tr class="bgColor-20">
278 <td' . $cellAttrib . '>' . $firstColContent . '</td>
279 <td colspan="' . ($this->returnNumberOfColumns() - 1) . '"><em>Not indexed</em></td>
280 </tr>';
281 }
282 // Checking for phash-rows which are NOT joined with the section table:
283 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('IP.*', 'index_phash IP', 'IP.data_page_id = ' . (int)$data['uid'] . ' AND IP.phash NOT IN (' . implode(',', $phashAcc) . ')');
284 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
285 $out .= '
286 <tr class="typo3-red">
287 <td colspan="' . $this->returnNumberOfColumns() . '"><strong>Warning:</strong> phash-row "' . $row['phash'] . '" didn\'t have a representation in the index_section table!</td>
288 </tr>';
289 $this->allPhashListed[] = $row['phash'];
290 }
291 return $out;
292 }
293
294 /**
295 * Render a single row of information about a indexing entry.
296 *
297 * @param array Row from query (combined phash table with sections etc).
298 * @param boolean Set if grouped to previous result; the icon of the element is not shown again.
299 * @param array Array of index_grlist records.
300 * @return array Array of table rows.
301 * @see indexed_info()
302 * @todo Define visibility
303 */
304 public function printPhashRow($row, $grouping = 0, $extraGrListRows) {
305 $lines = array();
306 // Title cell attributes will highlight TYPO3 pages with a slightly darker color (bgColor4) than attached medias. Also IF there are more than one section record for a phash row it will be red as a warning that something is wrong!
307 $titleCellAttribs = $row['count_val'] != 1 ? ' bgcolor="red"' : ($row['item_type'] === '0' ? ' class="bgColor4"' : '');
308 if ($row['item_type']) {
309 $arr = unserialize($row['cHashParams']);
310 $page = $arr['key'] ? ' [' . $arr['key'] . ']' : '';
311 } else {
312 $page = '';
313 }
314 $elTitle = $this->linkDetails($row['item_title'] ? htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['item_title'], 20) . $page) : '<em>[No Title]</em>', $row['phash']);
315 $cmdLinks = $this->printRemoveIndexed($row['phash'], 'Clear phash-row') . $this->printReindex($row, 'Re-index element');
316 switch ($this->pObj->MOD_SETTINGS['type']) {
317 case 1:
318 // Technical details:
319 // Display icon:
320 if (!$grouping) {
321 $lines[] = '<td>' . $this->makeItemTypeIcon($row['item_type'], ($row['data_filename'] ? $row['data_filename'] : $row['item_title'])) . '</td>';
322 } else {
323 $lines[] = '<td>&nbsp;</td>';
324 }
325 // Title displayed:
326 $lines[] = '<td' . $titleCellAttribs . '>' . $elTitle . '</td>';
327 // Remove-indexing-link:
328 $lines[] = '<td>' . $cmdLinks . '</td>';
329 // Various data:
330 $lines[] = '<td>' . $row['phash'] . '</td>';
331 $lines[] = '<td>' . $row['contentHash'] . '</td>';
332 if ($row['item_type'] === '0') {
333 $lines[] = '<td>' . ($row['data_page_id'] ? $row['data_page_id'] : '&nbsp;') . '</td>';
334 $lines[] = '<td>' . ($row['data_page_type'] ? $row['data_page_type'] : '&nbsp;') . '</td>';
335 $lines[] = '<td>' . ($row['sys_language_uid'] ? $row['sys_language_uid'] : '&nbsp;') . '</td>';
336 $lines[] = '<td>' . ($row['data_page_mp'] ? $row['data_page_mp'] : '&nbsp;') . '</td>';
337 } else {
338 $lines[] = '<td colspan="4">' . htmlspecialchars($row['data_filename']) . '</td>';
339 }
340 $lines[] = '<td>' . $row['gr_list'] . $this->printExtraGrListRows($extraGrListRows) . '</td>';
341 $lines[] = '<td>' . $this->printRootlineInfo($row) . '</td>';
342 $lines[] = '<td>' . ($row['page_id'] ? $row['page_id'] : '&nbsp;') . '</td>';
343 $lines[] = '<td>' . ($row['phash_t3'] != $row['phash'] ? $row['phash_t3'] : '&nbsp;') . '</td>';
344 $lines[] = '<td>' . ($row['freeIndexUid'] ? $row['freeIndexUid'] . ($row['freeIndexSetId'] ? '/' . $row['freeIndexSetId'] : '') : '&nbsp;') . '</td>';
345 $lines[] = '<td>' . ($row['recordUid'] ? $row['recordUid'] : '&nbsp;') . '</td>';
346 // cHash parameters:
347 $arr = unserialize($row['cHashParams']);
348 if (!is_array($arr)) {
349 $arr = array(
350 'cHash' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_general.xlf:LGL.error', TRUE)
351 );
352 }
353 $theCHash = $arr['cHash'];
354 unset($arr['cHash']);
355 if ($row['item_type']) {
356 // pdf...
357 $lines[] = '<td>' . ($arr['key'] ? 'Page ' . $arr['key'] : '') . '&nbsp;</td>';
358 } elseif ($row['item_type'] == 0) {
359 $lines[] = '<td>' . htmlspecialchars(GeneralUtility::implodeArrayForUrl('', $arr)) . '&nbsp;</td>';
360 } else {
361 $lines[] = '<td class="bgColor">&nbsp;</td>';
362 }
363 $lines[] = '<td>' . $theCHash . '</td>';
364 break;
365 case 2:
366 // Words and content:
367 // Display icon:
368 if (!$grouping) {
369 $lines[] = '<td>' . $this->makeItemTypeIcon($row['item_type'], ($row['data_filename'] ? $row['data_filename'] : $row['item_title'])) . '</td>';
370 } else {
371 $lines[] = '<td>&nbsp;</td>';
372 }
373 // Title displayed:
374 $lines[] = '<td' . $titleCellAttribs . '>' . $elTitle . '</td>';
375 // Remove-indexing-link:
376 $lines[] = '<td>' . $cmdLinks . '</td>';
377 // Query:
378 $ftrow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'index_fulltext', 'phash = ' . (int)$row['phash']);
379 $lines[] = '<td style="white-space: normal;">' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($ftrow['fulltextdata'], 3000)) . '<hr/><em>Size: ' . strlen($ftrow['fulltextdata']) . '</em>' . '</td>';
380 // Query:
381 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_words.baseword, index_rel.*', 'index_rel, index_words', 'index_rel.phash = ' . (int)$row['phash'] . ' AND index_words.wid = index_rel.wid', '', '', '', 'baseword');
382 $wordList = '';
383 if (is_array($ftrows)) {
384 $indexed_words = array_keys($ftrows);
385 sort($indexed_words);
386 $wordList = htmlspecialchars(implode(' ', $indexed_words));
387 $wordList .= '<hr/><em>Count: ' . count($indexed_words) . '</em>';
388 }
389 $lines[] = '<td style="white-space: normal;">' . $wordList . '</td>';
390 break;
391 default:
392 // Overview
393 // Display icon:
394 if (!$grouping) {
395 $lines[] = '<td>' . $this->makeItemTypeIcon($row['item_type'], ($row['data_filename'] ? $row['data_filename'] : $row['item_title'])) . '</td>';
396 } else {
397 $lines[] = '<td>&nbsp;</td>';
398 }
399 // Title displayed:
400 $lines[] = '<td' . $titleCellAttribs . '>' . $elTitle . '</td>';
401 // Remove-indexing-link:
402 $lines[] = '<td>' . $cmdLinks . '</td>';
403 $lines[] = '<td style="white-space: normal;">' . htmlspecialchars($row['item_description']) . '...</td>';
404 $lines[] = '<td>' . GeneralUtility::formatSize($row['item_size']) . '</td>';
405 $lines[] = '<td>' . BackendUtility::dateTimeAge($row['tstamp']) . '</td>';
406 }
407 return $lines;
408 }
409
410 /**
411 * Creates the header row for the table
412 *
413 * @return string HTML string (table row)
414 * @todo Define visibility
415 */
416 public function printPhashRowHeader() {
417 $lines = array();
418 switch ($this->pObj->MOD_SETTINGS['type']) {
419 case 1:
420 $lines[] = '<td>&nbsp;</td>';
421 $lines[] = '<td>&nbsp;</td>';
422 $lines[] = '<td>Title</td>';
423 $lines[] = '<td bgcolor="red">' . $this->printRemoveIndexed('ALL', 'Clear ALL phash-rows below!') . '</td>';
424 $lines[] = '<td>pHash</td>';
425 $lines[] = '<td>contentHash</td>';
426 $lines[] = '<td>&amp;id</td>';
427 $lines[] = '<td>&amp;type</td>';
428 $lines[] = '<td>&amp;L</td>';
429 $lines[] = '<td>&amp;MP</td>';
430 $lines[] = '<td>grlist</td>';
431 $lines[] = '<td>Rootline</td>';
432 $lines[] = '<td>page_id</td>';
433 $lines[] = '<td>phash_t3</td>';
434 $lines[] = '<td>CfgUid</td>';
435 $lines[] = '<td>RecUid</td>';
436 $lines[] = '<td>GET-parameters</td>';
437 $lines[] = '<td>&amp;cHash</td>';
438 break;
439 case 2:
440 $lines[] = '<td>&nbsp;</td>';
441 $lines[] = '<td>&nbsp;</td>';
442 $lines[] = '<td>Title</td>';
443 $lines[] = '<td bgcolor="red">' . $this->printRemoveIndexed('ALL', 'Clear ALL phash-rows below!') . '</td>';
444 $lines[] = '<td>Content<br />
445 <img src="clear.gif" width="300" height="1" alt="" /></td>';
446 $lines[] = '<td>Words<br />
447 <img src="clear.gif" width="300" height="1" alt="" /></td>';
448 break;
449 default:
450 $lines[] = '<td>&nbsp;</td>';
451 $lines[] = '<td>&nbsp;</td>';
452 $lines[] = '<td>Title</td>';
453 $lines[] = '<td bgcolor="red">' . $this->printRemoveIndexed('ALL', 'Clear ALL phash-rows below!') . '</td>';
454 $lines[] = '<td>Description</td>';
455 $lines[] = '<td>Size</td>';
456 $lines[] = '<td>Indexed:</td>';
457 }
458 $out = '<tr class="tableheader bgColor5">' . implode('', $lines) . '</tr>';
459 return $out;
460 }
461
462 /**
463 * Returns the number of columns depending on display type of list
464 *
465 * @return integer Number of columns in list:
466 * @todo Define visibility
467 */
468 public function returnNumberOfColumns() {
469 switch ($this->pObj->MOD_SETTINGS['type']) {
470 case 1:
471 return 18;
472 break;
473 case 2:
474 return 6;
475 break;
476 default:
477 return 7;
478 }
479 }
480
481 /*******************************
482 *
483 * Details display, phash row
484 *
485 *******************************/
486 /**
487 * Showing details for a particular phash row
488 *
489 * @param integer phash value to display details for.
490 * @return string HTML content
491 * @todo Define visibility
492 */
493 public function showDetailsForPhash($phash) {
494 $content = '';
495 $phash = (int)$phash;
496 // Selects the result row:
497 $phashRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'index_phash', 'phash = ' . $phash);
498 // If found, display:
499 if (is_array($phashRecord)) {
500 $content .= '<h4>phash row content:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($phashRecord);
501 // Getting debug information if any:
502 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'index_debug', 'phash = ' . $phash);
503 if (is_array($ftrows)) {
504 $debugInfo = unserialize($ftrows[0]['debuginfo']);
505 $lexer = $debugInfo['lexer'];
506 unset($debugInfo['lexer']);
507 $content .= '<h3>Debug information:</h3>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($debugInfo);
508 $content .= '<h4>Debug information / lexer splitting:</h4>' . '<hr/><strong>' . $lexer . '</strong><hr/>';
509 }
510 $content .= '<h3>Word statistics</h3>';
511 // Finding all words for this phash:
512 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_words.*, index_rel.*', 'index_rel, index_words', 'index_rel.phash = ' . $phash . ' AND index_words.wid = index_rel.wid', '', 'index_words.baseword', '');
513 $pageRec = BackendUtility::getRecord('pages', $phashRecord['data_page_id']);
514 $showStopWordCheckBox = $GLOBALS['BE_USER']->isAdmin();
515 $content .= $this->listWords($ftrows, 'All words found on page (' . count($ftrows) . '):', $showStopWordCheckBox, $pageRec);
516 if ($this->enableMetaphoneSearch) {
517 // Group metaphone hash:
518 $metaphone = array();
519 foreach ($ftrows as $row) {
520 $metaphone[$row['metaphone']][] = $row['baseword'];
521 }
522 $content .= $this->listMetaphoneStat($metaphone, 'Metaphone stats:');
523 }
524 // Finding top-20 on frequency for this phash:
525 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_words.baseword, index_words.metaphone, index_rel.*', 'index_rel, index_words', 'index_rel.phash = ' . $phash . ' AND index_words.wid = index_rel.wid
526 AND index_words.is_stopword=0', '', 'index_rel.freq DESC', '20');
527 $content .= $this->listWords($ftrows, 'Top-20 words by frequency:', 2);
528 // Finding top-20 on count for this phash:
529 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_words.baseword, index_words.metaphone, index_rel.*', 'index_rel, index_words', 'index_rel.phash = ' . $phash . ' AND index_words.wid = index_rel.wid
530 AND index_words.is_stopword=0', '', 'index_rel.count DESC', '20');
531 $content .= $this->listWords($ftrows, 'Top-20 words by count:', 2);
532 $content .= '<h3>Section records for this phash</h3>';
533 // Finding sections for this record:
534 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'index_section', 'index_section.phash = ' . $phash, '', '', '');
535 $content .= \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($ftrows);
536 // Add go-back link:
537 $content = $this->linkList() . $content . $this->linkList();
538 } else {
539 $content .= 'Error: No phash row found';
540 }
541 return $content;
542 }
543
544 /**
545 * Create table with list of words from $ftrows
546 *
547 * @param array Array of records selected from index_rel/index_words
548 * @param string Header string to show before table.
549 * @param boolean If set, the stopWord checkboxes will be shown in the word list. Only for admins. (because it is a global setting, not per-site).
550 * @param array The page record from which to load the keywords, if any.
551 * @return string HTML table
552 * @todo Define visibility
553 */
554 public function listWords($ftrows, $header, $stopWordBoxes = FALSE, $page = '') {
555 // Prepare keywords:
556 $keywords = is_array($page) ? array_flip(GeneralUtility::trimExplode(',', $page['keywords'], TRUE)) : '';
557 // Render list:
558 $trows = '';
559 $trows .= '
560 <tr class="tableheader bgColor5">
561 ' . ($stopWordBoxes ? '<td>' . htmlspecialchars('Stopword:') . '</td>' : '') . '
562 <td>' . htmlspecialchars('Word:') . '</td>
563 <td>' . htmlspecialchars('Count:') . '</td>
564 <td>' . htmlspecialchars('First:') . '</td>
565 <td>' . htmlspecialchars('Frequency:') . '</td>
566 <td>' . htmlspecialchars('Flags:') . '</td>
567 ' . (is_array($keywords) ? '<td>' . htmlspecialchars('Page keyword:') . '</td>' : '') . '
568 </tr>
569 ';
570 foreach ($ftrows as $row) {
571 $hiddenField = $stopWordBoxes != 2 ? '<input type="hidden" name="stopWord[' . $row['wid'] . ']" value="0" />' : '';
572 $trows .= '
573 <tr class="' . ($row['is_stopword'] ? 'bgColor' : 'bgColor4') . '">
574 ' . ($stopWordBoxes ? '<td align="center"' . ($row['is_stopword'] ? ' style="background-color:red;"' : '') . '>' . $hiddenField . '<input type="checkbox" name="stopWord[' . $row['wid'] . ']" value="1"' . ($row['is_stopword'] ? 'checked="checked"' : '') . ' /></td>' : '') . '
575 <td>' . $this->linkWordDetails(htmlspecialchars($row['baseword']), $row['wid']) . '</td>
576 <td>' . htmlspecialchars($row['count']) . '</td>
577 <td>' . htmlspecialchars($row['first']) . '</td>
578 <td>' . htmlspecialchars($row['freq']) . '</td>
579 <td>' . htmlspecialchars($this->flagsMsg($row['flags'])) . '</td>
580 ' . (is_array($keywords) ? '<td align="center"' . (isset($keywords[$row['baseword']]) ? ' class="bgColor2"' : '') . '><input type="hidden" name="pageKeyword[' . $row['baseword'] . ']" value="0" /><input type="checkbox" name="pageKeyword[' . $row['baseword'] . ']" value="1"' . (isset($keywords[$row['baseword']]) ? 'checked="checked"' : '') . ' /></td>' : '') . '
581 </tr>
582 ';
583 }
584 return '<h4>' . htmlspecialchars($header) . '</h4>' . '
585 <table border="0" cellspacing="1" cellpadding="2" class="c-list">
586 ' . $trows . '
587 </table>' . ($stopWordBoxes ? '<input type="submit" value="Change stop-word settings" name="_stopwords" onclick="document.webinfoForm.action=\'' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '\';" />' : '') . (is_array($keywords) ? '<input type="submit" value="Set page keywords" name="_pageKeywords" onclick="document.webinfoForm.action=\'' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '\';" /><input type="hidden" name="pageKeyword_pageUid" value="' . $page['uid'] . '" />' . '<br />Current keywords are: <em>' . htmlspecialchars(implode(', ', array_keys($keywords))) . '</em>' : '');
588 }
589
590 /**
591 * Displays table of metaphone groups larger than 1
592 *
593 * @param array Result from word selection (index_rel/index_words)
594 * @param string Header string
595 * @return string HTML table
596 * @todo Define visibility
597 */
598 public function listMetaphoneStat($ftrows, $header) {
599 $trows = '';
600 $trows .= '
601 <tr class="tableheader bgColor5">
602 <td>' . htmlspecialchars('Metaphone:') . '</td>
603 <td>' . htmlspecialchars('Hash:') . '</td>
604 <td>' . htmlspecialchars('Count:') . '</td>
605 <td>' . htmlspecialchars('Words:') . '</td>
606 </tr>
607 ';
608 foreach ($ftrows as $metaphone => $words) {
609 if (count($words) > 1) {
610 $trows .= '
611 <tr class="bgColor4">
612 <td>' . $this->linkMetaPhoneDetails($this->indexerObj->metaphone($words[0], 1), $metaphone) . '</td>
613 <td>' . htmlspecialchars($metaphone) . '</td>
614 <td>' . htmlspecialchars(count($words)) . '</td>
615 <td style="white-space: normal;">' . htmlspecialchars(implode(', ', $words)) . '</td>
616 </tr>
617 ';
618 }
619 }
620 return '<h4>' . htmlspecialchars($header) . '</h4>' . '<table border="0" cellspacing="1" cellpadding="2" class="c-list">
621 ' . $trows . '
622 </table>';
623 }
624
625 /**
626 * Wraps input string in a link that will display details for the word. Eg. which other pages has the word, metaphone associations etc.
627 *
628 * @param string String to wrap, possibly a title or so.
629 * @param integer wid value to show details for
630 * @return string Wrapped string
631 * @todo Define visibility
632 */
633 public function linkWordDetails($string, $wid) {
634 return '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('wid' => $wid, 'phash' => ''))) . '">' . $string . '</a>';
635 }
636
637 /**
638 * Wraps input string in a link to see more details for metaphone value
639 *
640 * @param string String to wrap
641 * @param integer Metaphone value
642 * @return string Wrapped string
643 * @todo Define visibility
644 */
645 public function linkMetaPhoneDetails($string, $metaphone) {
646 return '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('metaphone' => $metaphone, 'wid' => '', 'phash' => ''))) . '">' . $string . '</a>';
647 }
648
649 /**
650 * Creates message for flag value
651 *
652 * @param integer Flags integer
653 * @return string Message string
654 * @todo Define visibility
655 */
656 public function flagsMsg($flags) {
657 if ($flags > 0) {
658 return ($flags & 128 ? '<title>' : '') . ($flags & 64 ? '<meta/keywords>' : '') . ($flags & 32 ? '<meta/description>' : '') . ' (' . $flags . ')';
659 }
660 }
661
662 /*******************************
663 *
664 * Details display, words / metaphone
665 *
666 *******************************/
667 /**
668 * Show details for words
669 *
670 * @param integer Word ID (wid)
671 * @return string HTML content
672 * @todo Define visibility
673 */
674 public function showDetailsForWord($wid) {
675 // Select references to this word
676 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_phash.*, index_section.*, index_rel.*', 'index_rel, index_section, index_phash', 'index_rel.wid = ' . (int)$wid . ' AND index_rel.phash = index_section.phash' . ' AND index_section.phash = index_phash.phash', '', 'index_rel.freq DESC', '');
677 // Headers:
678 $content = '
679 <tr class="tableheader bgColor5">
680 <td>phash</td>
681 <td>page_id</td>
682 <td>data_filename</td>
683 <td>count</td>
684 <td>first</td>
685 <td>freq</td>
686 <td>flags</td>
687 </tr>';
688 if (is_array($ftrows)) {
689 foreach ($ftrows as $wDat) {
690 $content .= '
691 <tr class="bgColor4">
692 <td>' . $this->linkDetails(htmlspecialchars($wDat['phash']), $wDat['phash']) . '</td>
693 <td>' . htmlspecialchars($wDat['page_id']) . '</td>
694 <td>' . htmlspecialchars($wDat['data_filename']) . '</td>
695 <td>' . htmlspecialchars($wDat['count']) . '</td>
696 <td>' . htmlspecialchars($wDat['first']) . '</td>
697 <td>' . htmlspecialchars($wDat['freq']) . '</td>
698 <td>' . htmlspecialchars($wDat['flags']) . '</td>
699 </tr>';
700 }
701 }
702 // Compile table:
703 $content = '
704 <table border="0" cellspacing="1" cellpadding="2" class="c-list">' . $content . '
705 </table>';
706 // Add go-back link:
707 $content = $content . $this->linkList();
708 return $content;
709 }
710
711 /**
712 * Show details for metaphone value
713 *
714 * @param integer Metaphone integer hash
715 * @return string HTML content
716 * @todo Define visibility
717 */
718 public function showDetailsForMetaphone($metaphone) {
719 // Finding top-20 on frequency for this phash:
720 $ftrows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('index_words.*', 'index_words', 'index_words.metaphone = ' . (int)$metaphone, '', 'index_words.baseword', '');
721 if (count($ftrows)) {
722 $content .= '<h4>Metaphone: ' . $this->indexerObj->metaphone($ftrows[0]['baseword'], 1) . '</h4>';
723 $content .= '
724 <tr class="tableheader bgColor5">
725 <td>Word</td>
726 <td>Is stopword?</td>
727 </tr>';
728 if (is_array($ftrows)) {
729 foreach ($ftrows as $wDat) {
730 $content .= '
731 <tr class="bgColor4">
732 <td>' . $this->linkWordDetails(htmlspecialchars($wDat['baseword']), $wDat['wid']) . '</td>
733 <td>' . htmlspecialchars(($wDat['is_stopword'] ? 'YES' : 'No')) . '</td>
734 </tr>';
735 }
736 }
737 $content = '
738 <table border="0" cellspacing="1" cellpadding="2" class="c-list">' . $content . '
739 </table>';
740 if ($this->indexerObj->metaphone($ftrows[0]['baseword']) != $metaphone) {
741 $content .= 'ERROR: Metaphone string and hash did not match for some reason!?';
742 }
743 // Add go-back link:
744 $content = $content . $this->linkList();
745 }
746 return $content;
747 }
748
749 /*******************************
750 *
751 * Helper functions
752 *
753 *******************************/
754 /**
755 * Creates icon which clears indexes for a certain list of phash values.
756 *
757 * @param string List of phash integers
758 * @param string Alt-text for the garbage bin icon.
759 * @return string HTML img-tag with link around.
760 * @todo Define visibility
761 */
762 public function printRemoveIndexed($phash, $alt) {
763 return '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('deletePhash' => $phash))) . '" title="' . htmlspecialchars($alt) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-delete') . '</a>';
764 }
765
766 /**
767 * Button for re-indexing of documents
768 *
769 * @param array phash table result row.
770 * @param string Title attribute text for icon
771 * @return string HTML content; Icon wrapped in link.
772 * @todo Define visibility
773 */
774 public function printReindex($resultRow, $alt) {
775 if ($resultRow['item_type'] && $resultRow['item_type'] !== '0') {
776 return '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('reindex' => $resultRow['phash'], 'reindex_id' => $resultRow['page_id']))) . '">' . '<img ' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/refresh_n.gif', 'width="14" height="14"') . ' hspace="1" vspace="2" border="0" title="' . htmlspecialchars($alt) . '" alt="" />' . '</a>';
777 }
778 }
779
780 /**
781 * Wraps input string in a link that will display details for the phash value set.
782 *
783 * @param string String to wrap, possibly a title or so.
784 * @param integer phash value to show details for
785 * @return string Wrapped string
786 * @todo Define visibility
787 */
788 public function linkDetails($string, $phash) {
789 return '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('phash' => $phash))) . '">' . $string . '</a>';
790 }
791
792 /**
793 * Creates link back to listing
794 *
795 * @return string Link back to list
796 * @todo Define visibility
797 */
798 public function linkList() {
799 return '<br /><a href="index.php?id=' . $this->pObj->id . '">Back to list.</a><br />';
800 }
801
802 /**
803 * Wraps input string in a link that will display details for the phash value set.
804 *
805 * @param string String to wrap, possibly a title or so.
806 * @param integer phash value to show details for
807 * @return string Wrapped string
808 * @todo Define visibility
809 */
810 public function showPageDetails($string, $id) {
811 return '<a href="' . htmlspecialchars(('index.php?id=' . $id . '&SET[depth]=0&SET[type]=1')) . '">' . $string . '</a>';
812 }
813
814 /**
815 * Prints the gr_lists attached to a indexed entry.
816 *
817 * @param array Array of index_grlist records
818 * @return string HTML code.
819 * @todo Define visibility
820 */
821 public function printExtraGrListRows($extraGrListRows) {
822 if (count($extraGrListRows)) {
823 $lines = array();
824 foreach ($extraGrListRows as $r) {
825 $lines[] = $r['gr_list'];
826 }
827 return '<br />' . $GLOBALS['TBE_TEMPLATE']->dfw(implode('<br />', $lines));
828 }
829 }
830
831 /**
832 * Print path for indexing
833 *
834 * @param array Result row with content from index_section
835 * @return string Rootline information
836 * @todo Define visibility
837 */
838 public function printRootlineInfo($row) {
839 $uidCollection = array();
840 if ($row['rl0']) {
841 $uidCollection[0] = $row['rl0'];
842 if ($row['rl1']) {
843 $uidCollection[1] = $row['rl1'];
844 if ($row['rl2']) {
845 $uidCollection[2] = $row['rl2'];
846 // Additional levels:
847 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'])) {
848 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel) {
849 if ($row[$fieldName]) {
850 $uidCollection[$rootLineLevel] = $row[$fieldName];
851 }
852 }
853 }
854 }
855 }
856 }
857 // Return root line.
858 ksort($uidCollection);
859 return implode('/', $uidCollection);
860 }
861
862 /**
863 * Return icon for file extension
864 *
865 * @param string File extension / item type
866 * @param string Title attribute value in icon.
867 * @return string <img> tag for icon
868 * @todo Define visibility
869 */
870 public function makeItemTypeIcon($it, $alt = '') {
871 if (!isset($this->iconFileNameCache[$it])) {
872 if ($it === '0') {
873 $icon = 'EXT:indexed_search/pi/res/pages.gif';
874 } elseif ($this->external_parsers[$it]) {
875 $icon = $this->external_parsers[$it]->getIcon($it);
876 }
877 $fullPath = GeneralUtility::getFileAbsFileName($icon);
878 if ($fullPath) {
879 $info = @getimagesize($fullPath);
880 $iconPath = $GLOBALS['BACK_PATH'] . '../' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($fullPath);
881 $this->iconFileNameCache[$it] = is_array($info) ? '<img src="' . $iconPath . '" ' . $info[3] . ' title="###TITLE_ATTRIBUTE###" alt="" />' : '';
882 }
883 }
884 return str_replace('###TITLE_ATTRIBUTE###', htmlspecialchars($it . ': ' . $alt), $this->iconFileNameCache[$it]);
885 }
886
887 /********************************
888 *
889 * Reindexing
890 *
891 *******************************/
892 /**
893 * Re-indexing files/records attached to a page.
894 *
895 * @param integer Phash value
896 * @param integer The page uid for the section record (file/url could appear more than one place you know...)
897 * @return string HTML content
898 * @todo Define visibility
899 */
900 public function reindexPhash($phash, $pageId) {
901 // Query:
902 $resultRow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('ISEC.*, IP.*', 'index_phash IP, index_section ISEC', 'IP.phash = ISEC.phash
903 AND IP.phash = ' . (int)$phash . '
904 AND ISEC.page_id = ' . (int)$pageId);
905 $content = '';
906 if (is_array($resultRow)) {
907 if ($resultRow['item_type'] && $resultRow['item_type'] !== '0') {
908 // (Re)-Indexing file on page.
909 $indexerObj = GeneralUtility::makeInstance('TYPO3\\CMS\\IndexedSearch\\Indexer');
910 $indexerObj->backend_initIndexer($pageId, 0, 0, '', $this->getUidRootLineForClosestTemplate($pageId));
911 // URL or local file:
912 if ($resultRow['externalUrl']) {
913 $indexerObj->indexExternalUrl($resultRow['data_filename']);
914 } else {
915 $indexerObj->indexRegularDocument($resultRow['data_filename'], TRUE);
916 }
917 if ($indexerObj->file_phash_arr['phash'] != $resultRow['phash']) {
918 $content .= 'ERROR: phash (' . $indexerObj->file_phash_arr['phash'] . ') did NOT match ' . $resultRow['phash'] . ' for strange reasons!';
919 }
920 $content .= '<h4>Log for re-indexing of "' . htmlspecialchars($resultRow['data_filename']) . '":</h4>';
921 $content .= \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($indexerObj->internal_log);
922 $content .= '<h4>Hash-array, page:</h4>';
923 $content .= \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($indexerObj->hash);
924 $content .= '<h4>Hash-array, file:</h4>';
925 $content .= \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($indexerObj->file_phash_arr);
926 }
927 }
928 // Link back to list.
929 $content .= $this->linkList();
930 return $content;
931 }
932
933 /**
934 * Get rootline for closest TypoScript template root.
935 * Algorithm same as used in Web > Template, Object browser
936 *
937 * @param integer The page id to traverse rootline back from
938 * @return array Array where the root lines uid values are found.
939 * @todo Define visibility
940 */
941 public function getUidRootLineForClosestTemplate($id) {
942 $tmpl = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\ExtendedTemplateService');
943 // Defined global here!
944 $tmpl->tt_track = 0;
945 // Do not log time-performance information
946 $tmpl->init();
947 // Gets the rootLine
948 $sys_page = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
949 $rootLine = $sys_page->getRootLine($id);
950 $tmpl->runThroughTemplates($rootLine, 0);
951 // This generates the constants/config + hierarchy info for the template.
952 // Root line uids
953 $rootline_uids = array();
954 foreach ($tmpl->rootLine as $rlkey => $rldat) {
955 $rootline_uids[$rlkey] = $rldat['uid'];
956 }
957 return $rootline_uids;
958 }
959
960 /********************************
961 *
962 * SQL functions
963 *
964 *******************************/
965 /**
966 * Removes ALL data regarding a certain list of indexed phash-row
967 *
968 * @param string List of phash integers
969 * @param boolean If set, page cache is cleared as well.
970 * @return void
971 * @todo Define visibility
972 */
973 public function removeIndexedPhashRow($phashList, $clearPageCache = 1) {
974 // FIXME: This is only a workaround
975 if ($phashList == 'ALL') {
976 $this->drawTableOfIndexedPages();
977 $phashRows = $this->allPhashListed;
978 $this->allPhashListed = array();
979 } else {
980 $phashRows = GeneralUtility::trimExplode(',', $phashList, TRUE);
981 }
982 foreach ($phashRows as $phash) {
983 $phash = (int)$phash;
984 if ($phash > 0) {
985 if ($clearPageCache) {
986 // Clearing page cache:
987 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('page_id', 'index_section', 'phash=' . (int)$phash);
988 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
989 $idList = array();
990 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
991 $idList[] = (int)$row['page_id'];
992 }
993 $pageCache = $GLOBALS['typo3CacheManager']->getCache('cache_pages');
994 foreach ($idList as $pageId) {
995 $pageCache->flushByTag('pageId_' . $pageId);
996 }
997 }
998 }
999 // Removing old registrations for all tables.
1000 $tableArr = explode(',', 'index_phash,index_rel,index_section,index_grlist,index_fulltext,index_debug');
1001 foreach ($tableArr as $table) {
1002 $GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'phash=' . (int)$phash);
1003 }
1004 }
1005 }
1006 }
1007
1008 /**
1009 * Returns an array with gr_list records for a phash
1010 *
1011 * @param integer phash integer to look up on
1012 * @param string gr_list string to filter OUT of the result (first occurence)
1013 * @return array Array of records from index_grlist table
1014 * @todo Define visibility
1015 */
1016 public function getGrListEntriesForPhash($phash, $gr_list) {
1017 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'index_grlist', 'phash=' . (int)$phash);
1018 $lines = array();
1019 $isRemoved = 0;
1020 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1021 if (!$isRemoved && (string)$row['gr_list'] === (string)$gr_list) {
1022 $isRemoved = 1;
1023 } else {
1024 $lines[] = $row;
1025 }
1026 }
1027 return $lines;
1028 }
1029
1030 /**
1031 * Setting / Unsetting stopwords
1032 *
1033 * @param array Array of stop-words WIDs with 0/1 to set / unset
1034 * @return void
1035 * @todo Define visibility
1036 */
1037 public function processStopWords($stopWords) {
1038 if ($GLOBALS['BE_USER']->isAdmin()) {
1039 // Traverse words
1040 foreach ($stopWords as $wid => $state) {
1041 $fieldArray = array(
1042 'is_stopword' => $state
1043 );
1044 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('index_words', 'wid=' . $wid, $fieldArray);
1045 }
1046 }
1047 }
1048
1049 /**
1050 * Setting / Unsetting keywords in page header
1051 *
1052 * @param array Page keywords as keys in array with value 0 or 1 for set or unset.
1053 * @param integer The page uid of the header where the keywords are to be set.
1054 * @return void
1055 * @todo Define visibility
1056 */
1057 public function processPageKeywords($pageKeywords, $pageUid) {
1058 // Get pages current keywords
1059 $pageRec = BackendUtility::getRecord('pages', $pageUid);
1060 $keywords = array_flip(GeneralUtility::trimExplode(',', $pageRec['keywords'], TRUE));
1061 // Merge keywords:
1062 foreach ($pageKeywords as $key => $v) {
1063 if ($v) {
1064 $keywords[$key] = 1;
1065 } else {
1066 unset($keywords[$key]);
1067 }
1068 }
1069 // Compile new list:
1070 $data = array();
1071 $data['pages'][$pageUid]['keywords'] = implode(', ', array_keys($keywords));
1072 $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
1073 $tce->stripslashes_values = 0;
1074 $tce->start($data, array());
1075 $tce->process_datamap();
1076 }
1077
1078 }