[!!!][TASK] Rewrite backend modules of indexed_search 08/32708/27
authorGeorg Ringer <georg.ringer@gmail.com>
Wed, 10 Sep 2014 14:07:10 +0000 (16:07 +0200)
committerTymoteusz Motylewski <t.motylewski@gmail.com>
Thu, 11 Dec 2014 13:10:16 +0000 (14:10 +0100)
 * Move info modules and admin module to a central place
 * Use extbase & fluid
 * Add translations

The old modules are removed with a different commit to make it possible
to compare the output of old and new!

Releases: master
Resolves: #61511
Change-Id: Id750b0ad78e8ab115b917d4772281d3aceca6eee
Reviewed-on: http://review.typo3.org/32708
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Susanne Moog <typo3@susannemoog.de>
Reviewed-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Tested-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
21 files changed:
typo3/sysext/core/Documentation/Changelog/master/Breaking-61510-IndexedSearch.rst [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/Controller/AdministrationController.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/Controller/SearchFormController.php
typo3/sysext/indexed_search/Classes/Domain/Repository/AdministrationRepository.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/FileContentParser.php
typo3/sysext/indexed_search/Classes/ViewHelpers/Format/DateTimeViewHelper.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/ViewHelpers/Format/FlagValueViewHelper.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/ViewHelpers/Format/GroupListViewHelper.php [new file with mode: 0644]
typo3/sysext/indexed_search/Configuration/TypoScript/setup.txt
typo3/sysext/indexed_search/Resources/Private/Language/locallang.xlf
typo3/sysext/indexed_search/Resources/Private/Language/locallang_mod.xlf [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Layouts/Administration.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/ExternalDocuments.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Index.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Pages.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/StatisticDetails.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Administration/WordDetail.html [new file with mode: 0644]
typo3/sysext/indexed_search/ext_localconf.php
typo3/sysext/indexed_search/ext_tables.php
typo3/sysext/indexed_search/modfunc2/locallang.xlf

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-61510-IndexedSearch.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-61510-IndexedSearch.rst
new file mode 100644 (file)
index 0000000..a1e3998
--- /dev/null
@@ -0,0 +1,50 @@
+================================================
+Breaking: #61510 - Improvement of indexed_search
+================================================
+
+Description
+===========
+
+The extension indexed_search is improved in the backend and frontend.
+
+Backend
+-------
+
+Previously the functionality of indexed_search has been scattered to multiple modules.
+Information about indexed_search was available in a custom module in "Admin tools" and 2 sections in the "Info" module.
+
+The complete code has been moved to a central place, which is now a custom module in the area "Web" and has been rewritten
+by using Extbase & Fluid. Translations and a modern UI have been added as well.
+
+
+Impact
+======
+
+Changes in the Backend
+----------------------
+
+The previous user configuration for indexed_search modules is not working anymore.
+Therefore editors won't see the module anymore after login.
+
+Changes in the Frontend
+-----------------------
+
+The TypoScript configuration changed. If indexed_search is installed, it is automatically activated: ::
+
+       config.index_enable = 1
+       config.index_externals = 1
+
+
+
+Affected installations
+======================
+
+All installations using indexed_search
+
+Migration
+=========
+
+Backend
+-------
+
+Reconfigure the backend users and groups if users need to see the module of indexed_search.
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Classes/Controller/AdministrationController.php b/typo3/sysext/indexed_search/Classes/Controller/AdministrationController.php
new file mode 100644 (file)
index 0000000..9277ee9
--- /dev/null
@@ -0,0 +1,369 @@
+<?php
+namespace TYPO3\CMS\IndexedSearch\Controller;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Database\DatabaseConnection;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
+use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\IndexedSearch\Indexer;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * Administration controller
+ */
+class AdministrationController extends ActionController {
+
+       /**
+        * @var AdministrationRepository
+        */
+       protected $administrationRepository;
+
+       /**
+        * @var int Current page id
+        */
+       protected $pageUid = 0;
+
+       /**
+        * @var int Max lists per page
+        */
+       protected $maxListPerPage = 50;
+
+       /**
+        * @var array External parsers
+        */
+       protected $external_parsers = array();
+
+       /**
+        * @var array Configuration defined in the Extension Manager
+        */
+       protected $indexerConfig = array();
+
+       /**
+        * @var bool is metaphone enabled
+        */
+       protected $enableMetaphoneSearch = FALSE;
+
+       /**
+        * Indexer object
+        *
+        * @var \TYPO3\CMS\IndexedSearch\Indexer
+        */
+       protected $indexer;
+
+       /**
+        * Function will be called before every other action
+        *
+        * @return void
+        */
+       public function initializeAction() {
+               $this->pageUid = (int)GeneralUtility::_GET('id');
+               $this->maxListPerPage = GeneralUtility::_GP('listALL') ? 100000 : 100;
+               $this->indexerConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
+               $this->enableMetaphoneSearch = (bool)$this->indexerConfig['enableMetaphoneSearch'];
+               $this->indexer = GeneralUtility::makeInstance(Indexer::class);
+
+               parent::initializeAction();
+       }
+
+       /**
+        * Override the action name if found in the uc of the user
+        *
+        * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
+        * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
+        * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
+        */
+       public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) {
+               $vars = GeneralUtility::_GET('tx_indexedsearch_web_indexedsearchisearch');
+
+               $beUser = $this->getBackendUserAuthentication();
+               if (is_array($vars) && isset($vars['action']) && method_exists($this, $vars['action'] . 'Action')) {
+                       $action = $vars['action'];
+
+                       switch($action) {
+                               case 'saveStopwordsKeywords':
+                                       $action = 'statisticDetails';
+                                       break;
+                               case 'deleteIndexedItem':
+                                       $action = 'statistic';
+                                       break;
+                       }
+
+                       $beUser->uc['indexed_search']['action'] = $action;
+                       $beUser->uc['indexed_search']['arguments'] = $request->getArguments();
+                       $beUser->writeUC();
+               } elseif (isset($beUser->uc['indexed_search']['action'])) {
+                       if ($request instanceof WebRequest) {
+                               $request->setControllerActionName($beUser->uc['indexed_search']['action']);
+                       }
+                       if (isset($beUser->uc['indexed_search']['arguments'])) {
+                               $request->setArguments($beUser->uc['indexed_search']['arguments']);
+                       }
+               }
+
+               parent::processRequest($request, $response);
+       }
+
+       /**
+        * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
+        * @return void
+        */
+       public function injectAdministrationRepository(AdministrationRepository $administrationRepository) {
+               $this->administrationRepository = $administrationRepository;
+       }
+
+       /**
+        * Index action contains the most important statistics
+        *
+        * @return void
+        */
+       public function indexAction() {
+               $this->view->assignMultiple(array(
+                       'records' => $this->administrationRepository->getRecordsNumbers(),
+                       'phash' => $this->administrationRepository->getPageHashTypes()
+               ));
+
+               if ($this->pageUid) {
+                       $last24hours = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 24 * 60 * 60);
+                       $last30days = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 30 * 24 * 60 * 60);
+
+                       $this->view->assignMultiple(array(
+                               'pageUid' => $this->pageUid,
+                               'all' => $this->administrationRepository->getGeneralSearchStatistic('', $this->pageUid),
+                               'last24hours' => $this->administrationRepository->getGeneralSearchStatistic($last24hours, $this->pageUid),
+                               'last30days' => $this->administrationRepository->getGeneralSearchStatistic($last30days, $this->pageUid),
+                       ));
+               }
+       }
+
+       /**
+        * Statistics for pages
+        *
+        * @return void
+        */
+       public function pagesAction() {
+               $this->view->assign('records', $this->administrationRepository->getPageStatistic());
+       }
+
+       /**
+        * Statistics for external documents
+        *
+        * @return void
+        */
+       public function externalDocumentsAction() {
+               $this->view->assign('records', $this->administrationRepository->getExternalDocumentsStatistic());
+       }
+
+       /**
+        * Statistics for a given page hash
+        *
+        * @param int $pageHash
+        * @return void
+        */
+       public function statisticDetailsAction($pageHash = 0) {
+               $pageHash = (int)$pageHash;
+               $db = $this->getDatabaseConnection();
+               $pageHashRow = $db->exec_SELECTgetSingleRow('*', 'index_phash', 'phash = ' . (int)$pageHash);
+
+               if (!is_array($pageHashRow)) {
+                       $this->redirect('statistic');
+               }
+
+               $debugRow = $db->exec_SELECTgetRows('*', 'index_debug', 'phash = ' . (int)$pageHash);
+               $debugInfo = array();
+               $lexer = '';
+               if (is_array($debugRow)) {
+                       $debugInfo = unserialize($debugRow[0]['debuginfo']);
+                       $lexer = $debugInfo['lexer'];
+                       unset($debugInfo['lexer']);
+               }
+               $pageRecord = BackendUtility::getRecord('pages', $pageHashRow['data_page_id']);
+               $keywords = is_array($pageRecord) ? array_flip(GeneralUtility::trimExplode(',', $pageRecord['keywords'], TRUE)) : array();
+               $wordRecords = $db->exec_SELECTgetRows(
+                       'index_words.*, index_rel.*',
+                       'index_rel, index_words',
+                       'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid',
+                       '',
+                       'index_words.baseword'
+               );
+               foreach($wordRecords as $id => $row) {
+                       if (isset($keywords[$row['baseword']])) {
+                               $wordRecords[$id]['is_keyword'] = TRUE;
+                       }
+               }
+               $metaphoneRows = $metaphone = array();
+               if ($this->enableMetaphoneSearch && is_array($wordRecords)) {
+                       // Group metaphone hash
+                       foreach ($wordRecords as $row) {
+                               $metaphoneRows[$row['metaphone']][] = $row['baseword'];
+                       }
+
+                       foreach ($metaphoneRows as $hash => $words) {
+                               if (count($words) > 1) {
+                                       $metaphone[] = array(
+                                               'metaphone' => $this->indexer->metaphone($words[0], 1), $hash,
+                                               'words' => $words,
+                                               'hash' => $hash
+                                       );
+                               }
+                       }
+               }
+               $this->view->assignMultiple(array(
+                       'phash' => $pageHash,
+                       'phashRow' => $pageHashRow,
+                       'words' => $wordRecords,
+                       'sections' => $db->exec_SELECTgetRows(
+                               '*',
+                               'index_section',
+                               'index_section.phash = ' . (int)$pageHash
+                       ),
+                       'topCount' => $db->exec_SELECTgetRows(
+                               'index_words.baseword, index_words.metaphone, index_rel.*',
+                               'index_rel, index_words',
+                               'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
+                                        AND index_words.is_stopword=0',
+                               '',
+                               'index_rel.count DESC',
+                                '20'
+                        ),
+                       'topFrequency' => $db->exec_SELECTgetRows(
+                               'index_words.baseword, index_words.metaphone, index_rel.*',
+                               'index_rel, index_words',
+                               'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
+                                        AND index_words.is_stopword=0',
+                               '',
+                               'index_rel.freq DESC',
+                               '20'
+                       ),
+                       'debug' => $debugInfo,
+                       'lexer' => $lexer,
+                       'metaphone' => $metaphone,
+                       'page' => $pageRecord,
+                       'keywords' => $keywords
+       ));
+       }
+
+       /**
+        * Save stop words and keywords
+     *
+        * @param string $pageHash
+        * @param int $pageId
+        * @param array $stopwords
+        * @param array $keywords
+        * @return void
+        */
+       public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = array(), $keywords = array()) {
+               if ($this->getBackendUserAuthentication()->isAdmin()) {
+                       if (is_array($stopwords) && !empty($stopwords)) {
+                               $this->administrationRepository->saveStopWords($stopwords);
+                       }
+                       if (is_array($keywords) && !empty($keywords)) {
+                               $this->administrationRepository->saveKeywords($keywords, $pageId);
+                       }
+               }
+
+               $this->redirect('statisticDetails', NULL, NULL, array('pageHash' => $pageHash));
+       }
+
+       /**
+        * Statistics for a given word id
+        *
+        * @param int $id
+        * @param int $pageHash
+        * @return void
+        */
+       public function wordDetailAction($id = 0, $pageHash = 0) {
+               $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
+                       'index_phash.*, index_section.*, index_rel.*',
+                       'index_rel, index_section, index_phash',
+                       'index_rel.wid = ' . (int)$id . ' AND index_rel.phash = index_section.phash' . ' AND index_section.phash = index_phash.phash',
+                       '',
+                       'index_rel.freq DESC'
+               );
+
+               $this->view->assignMultiple(array(
+                       'rows' => $rows,
+                       'phash' => $pageHash
+               ));
+       }
+
+       /**
+        * General statistics
+        *
+        * @param int $depth
+        * @param string $mode
+        * @return void
+        */
+       public function statisticAction($depth = 1, $mode = 'overview') {
+               if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'])) {
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef) {
+                               /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
+                               $fileContentParser = GeneralUtility::getUserObj($_objRef);
+                               if ($fileContentParser->softInit($extension)) {
+                                       $this->external_parsers[$extension] = $fileContentParser;
+                               }
+                       }
+               }
+               $this->administrationRepository->external_parsers = $this->external_parsers;
+
+               $allLines = $this->administrationRepository->getTree($this->pageUid, $depth, $mode);
+
+               $this->view->assignMultiple(array(
+                       'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels')),
+                       'tree' => $allLines,
+                       'pageUid' => $this->pageUid,
+                       'mode' => $mode,
+                       'depth' => $depth
+               ));
+       }
+
+
+       /**
+        * Remove item from index
+        *
+        * @param string $id
+        * @param int $depth
+        * @param string $mode
+        * @return void
+        */
+       public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview') {
+               $this->administrationRepository->removeIndexedPhashRow($id, $this->pageUid, $depth);
+               $this->redirect('statistic', NULL, NULL, array('depth' => $depth, 'mode' => $mode));
+       }
+
+       /**
+        * @return DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
+       /**
+        * @return BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+
+       /**
+        * @return LanguageService
+        */
+       protected function getLanguageService() {
+               return $GLOBALS['LANG'];
+       }
+}
index 6ecd242..1f5420f 100644 (file)
@@ -29,7 +29,7 @@ class SearchFormController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
        public $prefixId = 'tx_indexedsearch';
 
        // Same as class name
-       public $scriptRelPath = 'pi/class.tx_indexedsearch.php';
+       public $scriptRelPath = 'Classes/Controller/SearchFormController.php';
 
        // Path to this script relative to the extension dir.
        public $extKey = 'indexed_search';
diff --git a/typo3/sysext/indexed_search/Classes/Domain/Repository/AdministrationRepository.php b/typo3/sysext/indexed_search/Classes/Domain/Repository/AdministrationRepository.php
new file mode 100644 (file)
index 0000000..d40c32a
--- /dev/null
@@ -0,0 +1,550 @@
+<?php
+namespace TYPO3\CMS\IndexedSearch\Domain\Repository;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Backend\Tree\View\PageTreeView;
+use TYPO3\CMS\Backend\Utility\IconUtility;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Dbal\Database\DatabaseConnection;
+use TYPO3\CMS\IndexedSearch\FileContentParser;
+
+/**
+ * Administration repository
+ */
+class AdministrationRepository {
+
+       /**
+        * List of fileContentParsers
+        *
+        * @var FileContentParser[]
+        */
+       public $external_parsers = array();
+
+       /**
+        * @var array
+        */
+       protected $allPhashListed = array();
+
+       /**
+        * @var array
+        */
+       protected $iconFileNameCache = array();
+
+       /**
+        * Get group list information
+        *
+        * @param int $phash
+        * @return array
+        */
+       public function getGrlistRecord($phash) {
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery('index_grlist.*', 'index_grlist', 'phash=' . (int)$phash);
+               $allRows = array();
+               $numberOfRows = $db->sql_num_rows($res);
+               while ($row = $db->sql_fetch_assoc($res)) {
+                       $row['pcount'] = $numberOfRows;
+                       $allRows[] = $row;
+               }
+               $db->sql_free_result($res);
+               return $allRows;
+       }
+
+       /**
+        * Get number of fulltext records
+        *
+        * @param int $phash
+        * @return int|bool
+        */
+       public function getNumberOfFulltextRecords($phash) {
+               return $this->getDatabaseConnection()->exec_SELECTcountRows('phash', 'index_fulltext', 'phash=' . (int)$phash);
+       }
+
+       /**
+        * Get number of words
+        *
+        * @param int $phash
+        * @return int|bool
+        */
+       public function getNumberOfWords($phash) {
+               return $this->getDatabaseConnection()->exec_SELECTcountRows('*', 'index_rel', 'phash=' . (int)$phash);
+       }
+
+       /**
+        * Get statistic of external documents
+        *
+        * @return array
+        */
+       public function getExternalDocumentsStatistic() {
+               $result = array();
+
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery(
+                       'count(*) AS pcount,index_phash.*',
+                       'index_phash',
+                       'item_type<>\'0\'',
+                       'phash_grouping,phash,cHashParams,data_filename,data_page_id,data_page_reg1,data_page_type,data_page_mp,gr_list,item_type,item_title,item_description,item_mtime,tstamp,item_size,contentHash,crdate,parsetime,sys_language_uid,item_crdate,externalUrl,recordUid,freeIndexUid,freeIndexSetId',
+                       'item_type'
+               );
+               while ($row = $db->sql_fetch_assoc($res)) {
+                       $this->addAdditionalInformation($row);
+
+                       $result[] = $row;
+
+                       if ($row['pcount'] > 1) {
+                               $res2 = $db->exec_SELECTquery(
+                                       'index_phash.*',
+                                       'index_phash',
+                                       'phash_grouping=' . (int)$row['phash_grouping'] . ' AND phash<>' . (int)$row['phash']
+                               );
+                               while ($row2 = $db->sql_fetch_assoc($res2)) {
+                                       $this->addAdditionalInformation($row2);
+                                       $result[] = $row2;
+                               }
+                               $db->sql_free_result($res2);
+                       }
+               }
+               $db->sql_free_result($res);
+
+               return $result;
+       }
+
+       /**
+        * Get count of the tables used for indexed_search
+        *
+        * @return array
+        */
+       public function getRecordsNumbers() {
+               $tables = array(
+                       'index_phash',
+                       'index_words',
+                       'index_rel',
+                       'index_grlist',
+                       'index_section',
+                       'index_fulltext',
+               );
+               $recordList = array();
+               foreach ($tables as $tableName) {
+                       $recordList[$tableName] = $this->getDatabaseConnection()->exec_SELECTcountRows('*', $tableName);
+               }
+               return $recordList;
+       }
+
+       /**
+        * Get hash types
+        *
+        * @return array
+        */
+       public function getPageHashTypes() {
+               $counts = array();
+               $types = array(
+                       'html' => 1,
+                       'htm' => 1,
+                       'pdf' => 2,
+                       'doc' => 3,
+                       'txt' => 4
+               );
+               $revTypes = array_flip($types);
+               $revTypes[0] = 'TYPO3 page';
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery('count(*),item_type', 'index_phash', '', 'item_type', 'item_type');
+               while ($row = $db->sql_fetch_row($res)) {
+                       $itemType = $row[1];
+                       $counts[] = array(
+                               'count' => $row[0],
+                               'name' => $revTypes[$itemType],
+                               'type' => $itemType,
+                               'uniqueCount' => $this->countUniqueTypes($itemType),
+                       );
+               }
+               $db->sql_free_result($res);
+
+               return $counts;
+       }
+
+       /**
+        * Count unique types
+        *
+        * @param string $itemType
+        * @return int
+        */
+       protected function countUniqueTypes($itemType) {
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery(
+                       'count(*)',
+                       'index_phash',
+                       'item_type=' . $db->fullQuoteStr($itemType, 'index_phash'),
+                       'phash_grouping'
+               );
+               $items = array();
+               while ($row = $db->sql_fetch_row($res)) {
+                       $items[] = $row;
+               }
+               $db->sql_free_result($res);
+
+               return count($items);
+       }
+
+       /**
+        * Get number of section records
+        *
+        * @param int $pageHash
+        * @return int
+        */
+       public function getNumberOfSections($pageHash) {
+               return $this->getDatabaseConnection()->exec_SELECTcountRows('phash', 'index_section', 'phash=' . (int)$pageHash);
+       }
+
+       /**
+        * Get page statistic
+        *
+        * @return array
+        */
+       public function getPageStatistic() {
+               $result = array();
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery(
+                       'count(*) AS pcount,index_phash.*',
+                       'index_phash',
+                       'data_page_id<>0',
+                       'phash_grouping,phash,cHashParams,data_filename,data_page_id,data_page_reg1,data_page_type,data_page_mp,gr_list,item_type,item_title,item_description,item_mtime,tstamp,item_size,contentHash,crdate,parsetime,sys_language_uid,item_crdate,externalUrl,recordUid,freeIndexUid,freeIndexSetId',
+                       'data_page_id'
+               );
+               while ($row = $db->sql_fetch_assoc($res)) {
+                       $this->addAdditionalInformation($row);
+                       $result[] = $row;
+
+                       if ($row['pcount'] > 1) {
+                               $res2 = $db->exec_SELECTquery(
+                                       'index_phash.*',
+                                       'index_phash',
+                                       'phash_grouping=' . (int)$row['phash_grouping'] . ' AND phash<>' . (int)$row['phash']
+                               );
+                               while ($row2 = $db->sql_fetch_assoc($res2)) {
+                                       $this->addAdditionalInformation($row2);
+                                       $result[] = $row2;
+                               }
+                               $db->sql_free_result($res2);
+                       }
+               }
+               $db->sql_free_result($res);
+
+               return $result;
+       }
+
+       /**
+        * Get general statistic
+        *
+        * @param string $additionalWhere
+        * @param int $pageUid
+        * @param int $max
+        * @return array|NULL
+        */
+       public function getGeneralSearchStatistic($additionalWhere, $pageUid, $max = 50) {
+               $queryParts = array(
+                       'SELECT' => 'word, COUNT(*) AS c',
+                       'FROM' => 'index_stat_word',
+                       'WHERE' => sprintf('pageid= %d ' . $additionalWhere, $pageUid),
+                       'GROUPBY' => 'word',
+                       'ORDERBY' => '',
+                       'LIMIT' => (int)$max
+               );
+               $db = $this->getDatabaseConnection();
+               $res = $db->exec_SELECTquery(
+                       $queryParts['SELECT'],
+                       $queryParts['FROM'],
+                       $queryParts['WHERE'],
+                       $queryParts['GROUPBY'],
+                       $queryParts['ORDERBY'],
+                       $queryParts['LIMIT']
+               );
+
+               $count = 0;
+               if ($res) {
+                       $count = $db->sql_num_rows($res);
+               }
+
+               $db->sql_free_result($res);
+
+               // exist several statistics for this page?
+               if ($count == 0) {
+                       // Limit access to pages of the current site
+                       $secureAddWhere = ' AND pageid IN (' . $this->extGetTreeList((int)$pageUid, 100, 0, '1=1') . ') ';
+                       $queryParts['WHERE'] = '1=1 ' . $additionalWhere . $secureAddWhere;
+               }
+
+               return $db->exec_SELECTgetRows(
+                       $queryParts['SELECT'],
+                       $queryParts['FROM'],
+                       $queryParts['WHERE'],
+                       $queryParts['GROUPBY'],
+                       $queryParts['ORDERBY'],
+                       $queryParts['LIMIT']
+               );
+       }
+
+       /**
+        * Add additional information to the result row
+        *
+        * @param array $row
+        * @return void
+        */
+       protected function addAdditionalInformation(array &$row) {
+               $grListRec = $this->getGrlistRecord($row['phash']);
+
+               $row['numberOfWords'] = $this->getNumberOfWords($row['phash']);
+               $row['numberOfSections'] = $this->getNumberOfSections($row['phash']);
+               $row['numberOfFulltext'] = $this->getNumberOfFulltextRecords($row['phash']);
+               $row['cHashParams'] = count(unserialize($row['cHashParams'])) ? unserialize($row['cHashParams']) : '';
+               $row['grList'] = $grListRec;
+       }
+
+       /**
+        * Get the page tree by using \TYPO3\CMS\Backend\Tree\View\PageTreeView
+        *
+        * @param int $pageId
+        * @param int $depth
+        * @param string $mode
+        * @return array
+        */
+       public function getTree($pageId, $depth = 4, $mode) {
+               $allLines = array();
+               $pageRecord = BackendUtility::getRecord('pages', (int)$pageId);
+               if (!$pageRecord) {
+                       return $allLines;
+               }
+               /** @var PageTreeView $tree */
+               $tree = GeneralUtility::makeInstance(PageTreeView::class);
+               $perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
+               $tree->init('AND ' . $perms_clause);
+               $HTML = IconUtility::getSpriteIconForRecord('pages', $pageRecord, array('title' => $pageRecord['title']));
+               $tree->tree[] = array(
+                       'row' => $pageRecord,
+                       'HTML' => $HTML
+               );
+
+               if ($depth > 0) {
+                       $tree->getTree((int)$pageId, $depth, '');
+               }
+               $db = $this->getDatabaseConnection();
+               foreach ($tree->tree as $singleLine) {
+                       $res = $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)$singleLine['row']['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',
+                               10 + 1
+                       );
+                       $lines = array();
+                       // Collecting phash values (to remove local indexing for)
+                       // Traverse the result set of phash rows selected:
+                       while ($row = $db->sql_fetch_assoc($res)) {
+                               $this->allPhashListed[] = $row['phash'];
+                               // Adds a display row:
+                               $row['icon'] = $this->makeItemTypeIcon($row['item_type']);
+                               $row['wordCount'] = count($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'
+                               ));
+
+                               if ($mode === 'content') {
+                                       $row['fulltextData'] = $db->exec_SELECTgetSingleRow(
+                                               '*',
+                                               'index_fulltext',
+                                               'phash = ' . $row['phash']);
+                                       $wordRecords = $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');
+                                       if (is_array($wordRecords)) {
+                                               $indexed_words = array_keys($wordRecords);
+                                               sort($indexed_words);
+                                               $row['allWords'] = $indexed_words;
+                                       }
+                               }
+
+                               $lines[] = $row;
+                       }
+
+                       $singleLine['lines'] = $lines;
+                       $allLines[] = $singleLine;
+               }
+
+               return $allLines;
+       }
+
+       /**
+        * Generates a list of Page-uid's from $id.
+        * The only pages excluded from the list are deleted pages.
+        *
+        * @param int $id page id
+        * @param int $depth to traverse down the page tree.
+        * @param int $begin is an optional integer that determines at which level in the tree to start collecting uid's. Zero means 'start right away', 1 = 'next level and out'
+        * @param string $perms_clause
+        * @return string Returns the list with a comma in the end + id itself
+        */
+       protected function extGetTreeList($id, $depth, $begin = 0, $perms_clause) {
+               $list = GeneralUtility::makeInstance(FrontendBackendUserAuthentication::class)->extGetTreeList($id, $depth, $begin, $perms_clause);
+
+               if (empty($list)) {
+                       $list = $id;
+               } else {
+                       $list = rtrim($list, ',') . ',' . $id;
+               }
+
+               return $list;
+       }
+
+       /**
+        * Remove indexed phash row
+        *
+        * @param string $phashList
+        * @param int $pageId
+        * @param int $depth
+        * @return void
+        */
+       public function removeIndexedPhashRow($phashList, $pageId, $depth = 4) {
+               if ($phashList === 'ALL') {
+                       $this->getTree($pageId, $depth, '');
+                       $phashRows = $this->allPhashListed;
+                       $this->allPhashListed = array();
+               } else {
+                       $phashRows = GeneralUtility::trimExplode(',', $phashList, TRUE);
+               }
+
+               $db = $this->getDatabaseConnection();
+               foreach ($phashRows as $phash) {
+                       $phash = (int)$phash;
+                       if ($phash > 0) {
+                               $idList = array();
+                               $res = $db->exec_SELECTquery('page_id', 'index_section', 'phash=' . $phash);
+                               while ($row = $db->sql_fetch_assoc($res)) {
+                                       $idList[] = (int)$row['page_id'];
+                               }
+                               $db->sql_free_result($res);
+
+                               if (!empty($idList)) {
+                                       /** @var FrontendInterface $pageCache */
+                                       $pageCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pages');
+                                       foreach ($idList as $pageId) {
+                                               $pageCache->flushByTag('pageId_' . $pageId);
+                                       }
+                               }
+
+                               // Removing old registrations for all tables.
+                               $tableArr = array('index_phash', 'index_rel', 'index_section', 'index_grlist', 'index_fulltext', 'index_debug');
+                               foreach ($tableArr as $table) {
+                                       $db->exec_DELETEquery($table, 'phash=' . $phash);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Save stop words
+        *
+        * @param array $words stop words
+        * @return void
+        */
+       public function saveStopWords(array $words) {
+               foreach ($words as $wid => $state) {
+                       $fieldArray = array(
+                               'is_stopword' => (int)$state
+                       );
+                       $this->getDatabaseConnection()->exec_UPDATEquery('index_words', 'wid=' . (int)$wid, $fieldArray);
+               }
+       }
+
+       /**
+        * Save keywords
+        *
+        * @param array $words keywords
+        * @param int $pageId page id
+        * @return void
+        */
+       public function saveKeywords(array $words, $pageId) {
+               // Get pages current keywords
+               $pageRec = BackendUtility::getRecord('pages', $pageId);
+               if (!is_array($pageRec)) {
+                       return;
+               }
+               $keywords = array_flip(GeneralUtility::trimExplode(',', $pageRec['keywords'], TRUE));
+               // Merge keywords:
+               foreach ($words as $key => $v) {
+                       if ($v) {
+                               $keywords[$key] = 1;
+                       } else {
+                               unset($keywords[$key]);
+                       }
+               }
+               // Compile new list:
+               $data = array();
+               $data['pages'][$pageId]['keywords'] = implode(', ', array_keys($keywords));
+               $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
+               $dataHandler->stripslashes_values = 0;
+               $dataHandler->start($data, array());
+               $dataHandler->process_datamap();
+       }
+
+       /**
+        * Collect the type icons
+        *
+        * @param string $itemType
+        * @return string
+        */
+       protected function makeItemTypeIcon($itemType) {
+               if (!isset($this->iconFileNameCache[$itemType])) {
+                       $icon = '';
+                       if ($itemType === '0') {
+                               $icon = 'EXT:indexed_search/pi/res/pages.gif';
+                       } elseif ($this->external_parsers[$itemType]) {
+                               $icon = $this->external_parsers[$itemType]->getIcon($itemType);
+                       }
+                       $this->iconFileNameCache[$itemType] = $icon;
+               }
+               return $this->iconFileNameCache[$itemType];
+       }
+
+       /**
+        * @return DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
+       /**
+        * @return BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+}
index d14e02f..6c7139a 100644 (file)
@@ -737,10 +737,9 @@ class FileContentParser {
         * @return string Relative file reference, resolvable by \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName()
         */
        public function getIcon($extension) {
-               if ($extension == 'htm') {
+               if ($extension === 'htm') {
                        $extension = 'html';
-               }
-               if ($extension == 'jpeg') {
+               } elseif ($extension === 'jpeg') {
                        $extension = 'jpg';
                }
                return 'EXT:indexed_search/pi/res/' . $extension . '.gif';
diff --git a/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/DateTimeViewHelper.php b/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/DateTimeViewHelper.php
new file mode 100644 (file)
index 0000000..a6fa041
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+namespace TYPO3\CMS\IndexedSearch\ViewHelpers\Format;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+
+/**
+ * DateTime viewhelper
+ */
+class DateTimeViewHelper extends AbstractViewHelper {
+
+
+       /**
+        * Render the given timestamp as date & time
+        *
+        * @return string
+        */
+       public function render() {
+               return htmlspecialchars(BackendUtility::datetime($this->renderChildren()));
+       }
+
+}
diff --git a/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/FlagValueViewHelper.php b/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/FlagValueViewHelper.php
new file mode 100644 (file)
index 0000000..52624ef
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+namespace TYPO3\CMS\IndexedSearch\ViewHelpers\Format;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * FlagValue viewhelper
+ */
+class FlagValueViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
+
+       /**
+        * Render additional flag information
+        *
+        * @param int $flags
+        * @return string
+        */
+       public function render($flags) {
+               $flags = (int)$flags;
+               if ($flags > 0) {
+                       $content = ($flags & 128 ? '<title>' : '')
+                               . ($flags & 64 ? '<meta/keywords>' : '')
+                               . ($flags & 32 ? '<meta/description>' : '');
+
+                       return htmlspecialchars($content);
+               }
+               return '';
+       }
+
+}
diff --git a/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/GroupListViewHelper.php b/typo3/sysext/indexed_search/Classes/ViewHelpers/Format/GroupListViewHelper.php
new file mode 100644 (file)
index 0000000..0922023
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+namespace TYPO3\CMS\IndexedSearch\ViewHelpers\Format;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+
+/**
+ * Group list viewhelper
+ */
+class GroupListViewHelper extends AbstractViewHelper {
+
+       /**
+        * Render the given group information as string
+        *
+        * @param array $groups
+        * @return string
+        */
+       public function render(array $groups = array()) {
+               $str = array();
+               foreach ($groups as $row) {
+                       $str[] = $row['gr_list'] === '0,-1' ? 'NL' : $row['gr_list'];
+               }
+               arsort($str);
+               return htmlspecialchars(implode('|', $str));
+       }
+
+}
\ No newline at end of file
index 751a3f3..39d801b 100644 (file)
@@ -1,5 +1,5 @@
-config.index_enable = 0
-config.index_externals = 0
+config.index_enable = 1
+config.index_externals = 1
 config.index_metatags = 1
 
  # Plugin configuration
index 7349395..92fabc6 100644 (file)
@@ -267,6 +267,208 @@ All search words are converted to lowercase.
                        <trans-unit id="displayResults" xml:space="preserve">
                                <source><![CDATA[Displaying results <strong>%1$s to %2$s</strong> out of <strong>%3$s</strong>]]></source>
                        </trans-unit>
+                       <trans-unit id="administration.menu.general" xml:space="preserve">
+                               <source>General statistics</source>
+                       </trans-unit>
+                       <trans-unit id="administration.menu.pages" xml:space="preserve">
+                               <source>List: Pages</source>
+                       </trans-unit>
+                       <trans-unit id="administration.menu.externalDocuments" xml:space="preserve">
+                               <source>List: External documents</source>
+                       </trans-unit>
+                       <trans-unit id="administration.menu.searchStatistic" xml:space="preserve">
+                               <source>Search statistic</source>
+                       </trans-unit>
+                       <trans-unit id="administration.menu.statistic" xml:space="preserve">
+                               <source>Detailed statistic</source>
+                       </trans-unit>
+                       <trans-unit id="administration.index.description" xml:space="preserve">
+                               <source>General statics</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.header" xml:space="preserve">
+                               <source>Statistics</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.name" xml:space="preserve">
+                               <source>Name</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.count" xml:space="preserve">
+                               <source>Count</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.headerTypes" xml:space="preserve">
+                               <source>Hash Header Types</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.word" xml:space="preserve">
+                               <source>Word</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.mostSearched.title" xml:space="preserve">
+                               <source>List of most searched words</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.mostSearched.description" xml:space="preserve">
+                               <source>Statistics for all pages. Select a page with indexed search form to see several statistics.</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.mostSearched.all" xml:space="preserve">
+                               <source>All</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.mostSearched.last30days" xml:space="preserve">
+                               <source>Last 30 days</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.mostSearched.last24hours" xml:space="preserve">
+                               <source>Last 24 hours</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.noResult" xml:space="preserve">
+                               <source>No result found</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.noResultForPage" xml:space="preserve">
+                               <source>No result for the selected page found.</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.selectPage" xml:space="preserve">
+                               <source>Please select a page in the page tree.</source>
+                       </trans-unit>
+                       <trans-unit id="administration.external.title" xml:space="preserve">
+                               <source>External documents</source>
+                       </trans-unit>
+                       <trans-unit id="field.fileName" xml:space="preserve">
+                               <source>Filename</source>
+                       </trans-unit>
+                       <trans-unit id="field.fileSize" xml:space="preserve">
+                               <source>Filesize</source>
+                       </trans-unit>
+                       <trans-unit id="field.wordCount" xml:space="preserve">
+                               <source>Word count</source>
+                       </trans-unit>
+                       <trans-unit id="field.words" xml:space="preserve">
+                               <source>Words</source>
+                       </trans-unit>
+                       <trans-unit id="field.mtime" xml:space="preserve">
+                               <source>Modification time</source>
+                       </trans-unit>
+                       <trans-unit id="field.indexed" xml:space="preserve">
+                               <source>Indexed</source>
+                       </trans-unit>
+                       <trans-unit id="field.updated" xml:space="preserve">
+                               <source>Updated</source>
+                       </trans-unit>
+                       <trans-unit id="field.parseTime" xml:space="preserve">
+                               <source>Parsetime</source>
+                       </trans-unit>
+                       <trans-unit id="field.groups" xml:space="preserve">
+                               <source>#sec/gr/full</source>
+                       </trans-unit>
+                       <trans-unit id="field.sub" xml:space="preserve">
+                               <source>Sub</source>
+                       </trans-unit>
+                       <trans-unit id="field.cHash" xml:space="preserve">
+                               <source>Chash</source>
+                       </trans-unit>
+                       <trans-unit id="field.count" xml:space="preserve">
+                               <source>Count</source>
+                       </trans-unit>
+                       <trans-unit id="field.first" xml:space="preserve">
+                               <source>First</source>
+                       </trans-unit>
+                       <trans-unit id="field.pHash" xml:space="preserve">
+                               <source>PageHash</source>
+                       </trans-unit>
+                       <trans-unit id="field.path" xml:space="preserve">
+                               <source>Path</source>
+                       </trans-unit>
+                       <trans-unit id="field.id" xml:space="preserve">
+                               <source>Page Id</source>
+                       </trans-unit>
+                       <trans-unit id="field.uniqueId" xml:space="preserve">
+                               <source>Unique Id</source>
+                       </trans-unit>
+                       <trans-unit id="field.type" xml:space="preserve">
+                               <source>Type</source>
+                       </trans-unit>
+                       <trans-unit id="field.title" xml:space="preserve">
+                               <source>Title</source>
+                       </trans-unit>
+                       <trans-unit id="field.language" xml:space="preserve">
+                               <source>Language</source>
+                       </trans-unit>
+                       <trans-unit id="field.frequency" xml:space="preserve">
+                               <source>Frequency</source>
+                       </trans-unit>
+                       <trans-unit id="field.flag" xml:space="preserve">
+                               <source>Flag</source>
+                       </trans-unit>
+                       <trans-unit id="field.metaphone" xml:space="preserve">
+                               <source>Metaphone</source>
+                       </trans-unit>
+                       <trans-unit id="field.content" xml:space="preserve">
+                               <source>Content</source>
+                       </trans-unit>
+                       <trans-unit id="administration.notIndexed" xml:space="preserve">
+                               <source>Not indexed?</source>
+                       </trans-unit>
+
+                       <trans-unit id="administration.document.description" xml:space="preserve">
+                               <source>Details for a single result row</source>
+                       </trans-unit>
+                       <trans-unit id="administration.document.words" xml:space="preserve">
+                               <source>All words found on page</source>
+                       </trans-unit>
+                       <trans-unit id="administration.document.topCount" xml:space="preserve">
+                               <source>Words by top count</source>
+                       </trans-unit>
+                       <trans-unit id="administration.document.topFrequency" xml:space="preserve">
+                               <source>Words by frequency</source>
+                       </trans-unit>
+                       <trans-unit id="administration.stopWords" xml:space="preserve">
+                               <source>Stopwords</source>
+                       </trans-unit>
+                       <trans-unit id="administration.stopWords.save" xml:space="preserve">
+                               <source>Save stopwords</source>
+                       </trans-unit>
+                       <trans-unit id="administration.keywords" xml:space="preserve">
+                               <source>Page keywords</source>
+                       </trans-unit>
+                       <trans-unit id="administration.keywords.current" xml:space="preserve">
+                               <source>Current page keywords</source>
+                       </trans-unit>
+                       <trans-unit id="administration.stopWordsKeywords.save" xml:space="preserve">
+                               <source>Save keywords and stop words</source>
+                       </trans-unit>
+                       <trans-unit id="administration.word.description" xml:space="preserve">
+                               <source>Detail view of a single word</source>
+                       </trans-unit>
+                       <trans-unit id="administration.linkBack" xml:space="preserve">
+                               <source>Back</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.sectionRecords" xml:space="preserve">
+                               <source>Section records for this phash</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.debug" xml:space="preserve">
+                               <source>Debug</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.lexer" xml:space="preserve">
+                               <source>Lexer</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.metaphone" xml:space="preserve">
+                               <source>Metaphone</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.view.overview" xml:space="preserve">
+                               <source>Overview</source>
+                       </trans-unit>
+                       <trans-unit id="administration.statistics.view.content" xml:space="preserve">
+                               <source>Words and content</source>
+                       </trans-unit>
+                       <trans-unit id="administration.phash.tableHeader" xml:space="preserve">
+                               <source>Phash row content</source>
+                       </trans-unit>
+                       <trans-unit id="administration.removeEntry" xml:space="preserve">
+                               <source>Remove entry</source>
+                       </trans-unit>
+                       <trans-unit id="administration.removeAllEntries" xml:space="preserve">
+                               <source>Remove all listed entries</source>
+                       </trans-unit>
+                       <trans-unit id="administration.back" xml:space="preserve">
+                               <source>Back</source>
+                       </trans-unit>
+                       <trans-unit id="administration.noPageSelected" xml:space="preserve">
+                               <source>Please select a page from the page tree.</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>
diff --git a/typo3/sysext/indexed_search/Resources/Private/Language/locallang_mod.xlf b/typo3/sysext/indexed_search/Resources/Private/Language/locallang_mod.xlf
new file mode 100644 (file)
index 0000000..bb78be3
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xliff version="1.0">
+       <file t3:id="1418239562" source-language="en" datatype="plaintext" original="messages" date="2014-09-19T16:43:33Z" product-name="indexed_search">
+               <header/>
+               <body>
+                       <trans-unit id="mlang_labels_tablabel" xml:space="preserve">
+                               <source>Administration module for the Indexing Engine</source>
+                       </trans-unit>
+                       <trans-unit id="mlang_labels_tabdescr" xml:space="preserve">
+                               <source>This lets you manage settings for the Indexing Engine which is provided by the frontend website. You can see statistics of indexed pages. Indexing must be enabled in the TypoScript template</source>
+                       </trans-unit>
+                       <trans-unit id="mlang_tabs_tab" xml:space="preserve">
+                               <source>Indexing</source>
+                       </trans-unit>
+               </body>
+       </file>
+</xliff>
diff --git a/typo3/sysext/indexed_search/Resources/Private/Layouts/Administration.html b/typo3/sysext/indexed_search/Resources/Private/Layouts/Administration.html
new file mode 100644 (file)
index 0000000..17f31c8
--- /dev/null
@@ -0,0 +1,24 @@
+<f:be.container>
+       <div class="typo3-fullDoc">
+               <div id="typo3-docheader">
+                       <div class="typo3-docheader-functions">
+                               <f:be.menus.actionMenu>
+                                       <f:be.menus.actionMenuItem label="{f:translate(key: 'administration.menu.general')}" controller="Administration" action="index" />
+                                       <f:be.menus.actionMenuItem label="{f:translate(key: 'administration.menu.pages')}" controller="Administration" action="pages" />
+                                       <f:be.menus.actionMenuItem label="{f:translate(key: 'administration.menu.externalDocuments')}" controller="Administration" action="externalDocuments" />
+                                       <f:be.menus.actionMenuItem label="{f:translate(key: 'administration.menu.statistic')}" controller="Administration" action="statistic" />
+                               </f:be.menus.actionMenu>
+                       </div>
+                       <div class="typo3-docheader-buttons">
+                               <f:render section="Buttons" />
+                       </div>
+               </div>
+
+               <div id="typo3-docbody">
+                       <div id="typo3-inner-docbody">
+                               <h1>Indexing Engine Statistics</h1>
+                               <f:render section="Content" />
+                       </div>
+               </div>
+       </div>
+</f:be.container>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/ExternalDocuments.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/ExternalDocuments.html
new file mode 100644 (file)
index 0000000..e26a28d
--- /dev/null
@@ -0,0 +1,71 @@
+{namespace is=TYPO3\CMS\IndexedSearch\ViewHelpers}
+
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <h2><f:translate key="administration.external.title"/></h2>
+
+       <f:if condition="{records}">
+               <table class="t3-table">
+                       <thead>
+                               <tr>
+                                       <th><f:translate key="field.fileName"/></th>
+                                       <th><f:translate key="field.fileSize"/></th>
+                                       <th><f:translate key="field.wordCount"/></th>
+                                       <th><f:translate key="field.mtime"/></th>
+                                       <th><f:translate key="field.indexed"/></th>
+                                       <th><f:translate key="field.updated"/></th>
+                                       <th><f:translate key="field.parseTime"/></th>
+                                       <th><f:translate key="field.groups"/></th>
+                                       <th><f:translate key="field.sub"/></th>
+                                       <th><f:translate key="field.cHash"/></th>
+                                       <th><f:translate key="field.pHash"/></th>
+                                       <th><f:translate key="field.path"/></th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               <f:for each="{records}" as="data">
+                                       <tr>
+                                               <td>
+                                                       <f:format.crop maxCharacters="30">{data.item_title}</f:format.crop>
+                                               </td>
+                                               <td>
+                                                       <f:format.bytes decimals="1">{data.item_size}</f:format.bytes>
+                                               </td>
+                                               <td>{data.numberOfWords}</td>
+                                               <td>
+                                                       <is:format.dateTime>{data.item_mtime}</is:format.dateTime>
+                                               </td>
+                                               <td>
+                                                       <is:format.dateTime>{data.crdate}</is:format.dateTime>
+                                               </td>
+                                               <td>
+                                                       <f:if condition="{date.tstamp}=={date.crdate}">
+                                                               <f:then></f:then>
+                                                               <f:else>
+                                                                       <is:format.dateTime>{data.tstamp}</is:format.dateTime>
+                                                               </f:else>
+                                                       </f:if>
+                                               </td>
+                                               <td>{data.parsetime}</td>
+                                               <td>{data.numberOfSections}/{data.grList.0.pcount}/{data.numberOfFulltext}</td>
+                                               <td>{data.pcount}</td>
+                                               <td>
+                                                       <f:if condition="{data.cHashParams}">
+                                                               <f:for each="{data.cHashParams}" as="value" key="key">
+                                                                       {key}={value}<br>
+                                                               </f:for>
+                                                       </f:if>
+                                               </td>
+                                               <td>{data.phash}</td>
+                                               <td>
+                                                       <f:format.crop maxCharacters="100">{data.data_filename}</f:format.crop>
+                                               </td>
+                                       </tr>
+                               </f:for>
+                       </tbody>
+               </table>
+       </f:if>
+</f:section>
+
+<f:section name="Buttons"></f:section>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Index.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Index.html
new file mode 100644 (file)
index 0000000..594a63c
--- /dev/null
@@ -0,0 +1,124 @@
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <p class="lead"><f:translate key="administration.index.description" /></p>
+
+       <div class="row">
+               <div class="col-md-6">
+                       <h4><f:translate key="administration.statistics.header" /></h4>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th><f:translate key="administration.statistics.name" /></th>
+                                               <th><f:translate key="administration.statistics.count" /></th>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{records}" as="count" key="name">
+                                               <tr>
+                                                       <td>{name}</td>
+                                                       <td>{count}</td>
+                                               </tr>
+                                       </f:for>
+                               </tbody>
+                       </table>
+               </div>
+               <div class="col-md-6">
+                       <h4><f:translate key="administration.statistics.headerTypes" /></h4>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th><f:translate key="administration.statistics.name" /></th>
+                                               <th><f:translate key="administration.statistics.count" /></th>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{phash}" as="data">
+                                               <tr>
+                                                       <td>{data.name} ({data.type})</td>
+                                                       <td>{data.count} / {data.uniqueCount}</td>
+                                               </tr>
+                                       </f:for>
+                               </tbody>
+                       </table>
+               </div>
+       </div>
+
+       <h3>
+               <f:translate key="administration.statistics.mostSearched.title"/>
+       </h3>
+       <p>
+               <f:translate key="administration.statistics.mostSearched.description"/>
+       </p>
+       <f:if condition="{pageUid}">
+               <f:then>
+                       <f:if condition="{all}">
+                               <f:then>
+                                       <div class="row">
+                                               <div class="col-md-4">
+                                                       <f:render section="statistic" arguments="{statistic:all,title:'all'}"/>
+                                               </div>
+                                               <div class="col-md-4">
+                                                       <f:render section="statistic" arguments="{statistic:last24hours,title:'last24hours'}"/>
+                                               </div>
+                                               <div class="col-md-4">
+                                                       <f:render section="statistic" arguments="{statistic:last30days,title:'last30days'}"/>
+                                               </div>
+                                       </div>
+                               </f:then>
+                               <f:else>
+                                       <div class="typo3-message message-notice">
+                                               <div class="message-body">
+                                                       <f:translate key="administration.statistics.noResultForPage"/>
+                                               </div>
+                                       </div>
+                               </f:else>
+                       </f:if>
+
+               </f:then>
+               <f:else>
+                       <div class="typo3-message message-information">
+                               <div class="message-body">
+                                       <f:translate key="administration.statistics.selectPage"/>
+                               </div>
+                       </div>
+               </f:else>
+       </f:if>
+</f:section>
+
+<f:section name="statistic">
+       <h4>
+               <f:translate key="administration.statistics.mostSearched.{title}"/>
+       </h4>
+       <f:if condition="{statistic}">
+               <f:then>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th class="nowrap">&nbsp;</th>
+                                               <th><f:translate key="administration.statistics.mostSearched."/></th>
+                                               <th><f:translate key="administration.statistics.count"/></th>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{statistic}" as="line" iteration="i">
+                                               <tr>
+                                                       <td class="nowrap"><strong>{i.cycle}.</strong></td>
+                                                       <td>{line.word}</td>
+                                                       <td>{line.c}</td>
+                                               </tr>
+                                       </f:for>
+                               </tbody>
+                       </table>
+               </f:then>
+               <f:else>
+                       <div class="typo3-message message-notice">
+                               <div class="message-body">
+                                       <f:translate key="administration.statistics.noResult"/>
+                               </div>
+                       </div>
+               </f:else>
+       </f:if>
+</f:section>
+
+<f:section name="Buttons"></f:section>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Pages.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Pages.html
new file mode 100644 (file)
index 0000000..a75efe8
--- /dev/null
@@ -0,0 +1,74 @@
+{namespace is=TYPO3\CMS\IndexedSearch\ViewHelpers}
+
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <h2>Pages</h2>
+       <f:if condition="{records}">
+               <table class="t3-table">
+                       <thead>
+                               <tr>
+                                       <th><f:translate key="field.id"/>/<f:translate key="field.type"/></th>
+                                       <th><f:translate key="field.title"/></th>
+                                       <th><f:translate key="field.fileSize"/></th>
+                                       <th><f:translate key="field.wordCount"/></th>
+                                       <th><f:translate key="field.mtime"/></th>
+                                       <th><f:translate key="field.indexed"/></th>
+                                       <th><f:translate key="field.updated"/></th>
+                                       <th><f:translate key="field.parseTime"/></th>
+                                       <th><f:translate key="field.groups"/></th>
+                                       <th><f:translate key="field.sub"/></th>
+                                       <th><f:translate key="field.language"/></th>
+                                       <th><f:translate key="field.cHash"/></th>
+                                       <th><f:translate key="field.pHash"/></th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                       <f:for each="{records}" as="data">
+                               <tr>
+                                       <td>
+                                               {data.data_page_id}
+                                               <f:if condition="{data.data_page_type}">/ {data.data_page_type}</f:if>
+                                               {data.0}
+                                       </td>
+                                       <td>
+                                               <f:format.crop maxCharacters="30">{data.item_title}</f:format.crop>
+                                       </td>
+                                       <td>
+                                               <f:format.bytes decimals="1">{data.item_size}</f:format.bytes>
+                                       </td>
+                                       <td>{data.numberOfWords}</td>
+                                       <td>
+                                               <is:format.dateTime>{data.item_mtime}</is:format.dateTime>
+                                       </td>
+                                       <td>
+                                               <is:format.dateTime>{data.crdate}</is:format.dateTime>
+                                       </td>
+                                       <td>
+                                               <f:if condition="{date.tstamp}=={date.crdate}">
+                                                       <f:then></f:then>
+                                                       <f:else>
+                                                               <is:format.dateTime>{data.tstamp}</is:format.dateTime>
+                                                       </f:else>
+                                               </f:if>
+                                       </td>
+                                       <td>{data.parsetime}</td>
+                                       <td>{data.numberOfSections}/{data.grList.0.pcount}/{data.numberOfFulltext}</td>
+                                       <td>{data.pcount} / {is:format.groupList(groups:data.grList)}</td>
+                                       <td>{data.sys_language_uid}</td>
+                                       <td>
+                                               <f:if condition="{data.cHashParams}">
+                                                       <f:for each="{data.cHashParams}" as="value" key="key">
+                                                               {key}={value}<br>
+                                                       </f:for>
+                                               </f:if>
+                                       </td>
+                                       <td>{data.phash}</td>
+                               </tr>
+                       </f:for>
+                       </tbody>
+               </table>
+       </f:if>
+</f:section>
+
+<f:section name="Buttons"></f:section>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/Statistic.html
new file mode 100644 (file)
index 0000000..917b47f
--- /dev/null
@@ -0,0 +1,125 @@
+{namespace is=TYPO3\CMS\IndexedSearch\ViewHelpers}
+
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <f:if condition="{tree}">
+               <f:then>
+                       <f:form name="statistic" action="statistic" class="form-horizontal" arguments="{id:pageUid}">
+                               <div class="form-group">
+                                       <div class="col-sm-12">
+                                               <f:form.select name="mode" options="{
+                                                       overview:'{f:translate(key:\'administration.statistics.view.overview\')}',
+                                                       content:'{f:translate(key:\'administration.statistics.view.content\')}'
+                                                       }" value="{mode}" additionalAttributes="{onchange:'this.form.submit();'}"/>
+                                               <f:form.select name="depth" options="{levelTranslations}" value="{depth}" additionalAttributes="{onchange:'this.form.submit();'}"/>
+                                       </div>
+                               </div>
+                       </f:form>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th></th>
+                                               <th>
+                                                       <f:be.buttons.icon title="{f:translate(key:'administration.removeAllEntries')}" icon="actions-edit-delete" uri="{f:uri.action(action:'deleteIndexedItem',arguments:'{id:\'ALL\',depth:depth,mode:mode}')}"/>
+                                               </th>
+                                               <th>
+                                                       <f:translate key="field.fileName"/>
+                                               </th>
+                                               <f:switch expression="{mode}">
+                                                       <f:case value="content">
+                                                               <th>
+                                                                       <f:translate key="field.content" />
+                                                               </th>
+                                                               <th>
+                                                                       <f:translate key="field.words" />
+                                                               </th>
+                                                       </f:case>
+                                                       <f:case default="TRUE">
+                                                               <th>
+                                                                       <f:translate key="field.wordCount"/>
+                                                               </th>
+                                                               <th>
+                                                                       <f:translate key="field.fileSize"/>
+                                                               </th>
+                                                               <th>
+                                                                       <f:translate key="field.indexed"/>
+                                                               </th>
+                                                       </f:case>
+                                               </f:switch>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{tree}" as="line">
+                                               <f:if condition="{line.lines}">
+                                                       <f:then>
+                                                               <f:for each="{line.lines}" as="l" iteration="i">
+                                                                       <tr>
+                                                                               <f:then>
+                                                                                       <td class="nowrap">
+                                                                                               {line.HTML -> f:format.raw()}
+                                                                                               <f:if condition="{i.index} == 0"> {line.row.title}</f:if>
+                                                                                       </td>
+                                                                                       <td>
+                                                                                               <f:be.buttons.icon  title="{f:translate(key:'administration.removeEntry')}" icon="actions-edit-delete" uri="{f:uri.action(action:'deleteIndexedItem',arguments:'{id:l.phash,depth:depth,mode:mode}')}"/>
+                                                                                       </td>
+                                                                                       <td>
+                                                                                               <f:image src="{l.icon}"/>
+                                                                                               <f:link.action action="statisticDetails" arguments="{pageHash:l.phash}">{l.item_title}</f:link.action>
+                                                                                       </td>
+                                                                                       <f:switch expression="{mode}">
+                                                                                               <f:case value="content">
+                                                                                                       <td>
+                                                                                                               {l.fulltextData.fulltextdata}
+                                                                                                       </td>
+                                                                                                       <td>
+                                                                                                               <f:for each="{l.allWords}" as="w">
+                                                                                                                       {w}
+                                                                                                               </f:for>
+                                                                                                               <br><br>
+                                                                                                               <em>{f:translate(key:'administration.statistics.count')}: {f:count(subject:l.allWords)}</em>
+                                                                                                       </td>
+                                                                                               </f:case>
+                                                                                               <f:case default="TRUE">
+                                                                                                       <td>{l.wordCount}</td>
+                                                                                                       <td>
+                                                                                                               <f:format.bytes decimals="1">{l.item_size}</f:format.bytes>
+                                                                                                       </td>
+                                                                                                       <td>
+                                                                                                               <is:format.dateTime>{l.tstamp}</is:format.dateTime>
+                                                                                                       </td>
+                                                                                               </f:case>
+                                                                                       </f:switch>
+                                                                               </f:then>
+                                                                       </tr>
+                                                               </f:for>
+                                                       </f:then>
+                                                       <f:else>
+                                                               <tr>
+                                                                       <td class="nowrap">{line.HTML -> f:format.raw()} {line.row.title}</td>
+                                                                       <f:switch expression="{mode}">
+                                                                               <f:case value="content">
+                                                                                       <td colspan="5">
+                                                                                               <f:translate key="administration.notIndexed" />
+                                                                                       </td>
+                                                                               </f:case>
+                                                                               <f:case default="TRUE">
+                                                                                       <td colspan="5">
+                                                                                               <f:translate key="administration.notIndexed"/>
+                                                                                       </td>
+                                                                               </f:case>
+                                                                       </f:switch>
+                                                               </tr>
+                                                       </f:else>
+                                               </f:if>
+                                       </f:for>
+                                       </tbody>
+                       </table>
+               </f:then>
+               <f:else>
+                       <h2><f:translate key="administration.noPageSelected"/></h2>
+               </f:else>
+       </f:if>
+</f:section>
+
+<f:section name="Buttons"></f:section>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/StatisticDetails.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/StatisticDetails.html
new file mode 100644 (file)
index 0000000..f7acc9f
--- /dev/null
@@ -0,0 +1,202 @@
+{namespace is=TYPO3\CMS\IndexedSearch\ViewHelpers}
+
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <p class="lead"><f:translate key="administration.document.description"/></p>
+       <f:flashMessages renderMode="div"/>
+       <f:if condition="{phashRow}">
+               <f:then>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th colspan="2"><f:translate key="administration.phash.tableHeader"/></th>
+                                       </tr>
+                               </thead>
+                               <f:for each="{phashRow}" as="value" key="key">
+                                       <tr>
+                                               <td><strong>{key}</strong></td>
+                                               <td>{value}</td>
+                                       </tr>
+                               </f:for>
+                       </table>
+
+                       <div class="row">
+                               <div class="col-md-12">
+                                       <f:render section="wordlisting" arguments="{words:words,phash:phash,page:page,keywords:keywords,title:'words'}"/>
+                               </div>
+                       </div>
+
+                       <div class="row">
+                               <div class="col-md-6">
+                                       <f:render section="wordlisting" arguments="{words:topCount,phash:phash,title:'topCount'}"/>
+                               </div>
+                               <div class="col-md-6">
+                                       <f:render section="wordlisting" arguments="{words:topFrequency,phash:phash,title:'topFrequency'}"/>
+                               </div>
+                       </div>
+
+                       <f:if condition="{debug}">
+                               <h4>
+                                       <f:translate key="administration.statistics.debug"/>
+                               </h4>
+                               <f:debug inline="1" title="">{debug}</f:debug>
+                       </f:if>
+                       <f:if condition="{lexer}">
+                               <h4>
+                                       <f:translate key="administration.statistics.lexer"/>
+                               </h4>
+                               <f:format.raw>{lexer}</f:format.raw>
+                       </f:if>
+
+                       <f:if condition="{metaphone}">
+                               <h4>
+                                       <f:translate key="administration.statistics.metaphone"/>
+                               </h4>
+                               <table class="t3-table">
+                                       <thead>
+                                       <tr>
+                                               <th>
+                                                       <f:translate key="field.metaphone"/>
+                                               </th>
+                                               <th>
+                                                       <f:translate key="field.pHash"/>
+                                               </th>
+                                               <th>
+                                                       <f:translate key="field.wordCount"/>
+                                               </th>
+                                               <th>
+                                                       <f:translate key="field.words"/>
+                                               </th>
+                                       </tr>
+                                       </thead>
+                                       <tbody>
+                                       <f:for each="{metaphone}" as="row">
+                                               <tr>
+                                                       <td>{row.metaphone}</td>
+                                                       <td>{row.hash}</td>
+                                                       <td>{f:count(subject:row.words)}</td>
+                                                       <td><f:for each="{row.words}" as="word">
+                                                               {word},
+                                                       </f:for></td>
+                                               </tr>
+                                       </f:for>
+                                       </tbody>
+                               </table>
+                       </f:if>
+
+                       <f:if condition="{sections}">
+                               <h4><f:translate key="administration.statistics.sectionRecords"/></h4>
+                               <table class="t3-table">
+                                       <thead>
+                                               <tr>
+                                                       <th><f:translate key="field.pHash"/></th>
+                                                       <th>rl0</th>
+                                                       <th>rl1</th>
+                                                       <th>rl2</th>
+                                                       <th><f:translate key="field.id"/></th>
+                                                       <th><f:translate key="field.uniqueId"/></th>
+                                               </tr>
+                                       </thead>
+                                       <tbody>
+                                               <f:for each="{sections}" as="row">
+                                                       <tr>
+                                                               <td>{row.phash}</td>
+                                                               <td>{row.rl0}</td>
+                                                               <td>{row.rl1}</td>
+                                                               <td>{row.rl2}</td>
+                                                               <td>{row.page_id}</td>
+                                                               <td>{row.uniqueid}</td>
+                                                       </tr>
+                                               </f:for>
+                                       </tbody>
+                               </table>
+                       </f:if>
+               </f:then>
+               <f:else>
+                       <div class="typo3-message message-error">
+                               <div class="message-body">
+                                       no record found
+                               </div>
+                       </div>
+               </f:else>
+       </f:if>
+</f:section>
+
+<f:section name="wordlisting">
+       <h4><f:translate key="administration.document.{title}"/>
+       <f:if condition="{title}=='words'">
+               ({f:count(subject:words)})
+       </f:if>
+       </h4>
+       <f:if condition="{words}">
+               <f:form method="post" action="saveStopwordsKeywords" name="stopwordskeywords" arguments="{pageHash:phash}">
+                       <f:form.hidden name="pageHash" value="{phash}"/>
+                       <f:form.hidden name="pageId" value="{page.uid}"/>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th><f:translate key="administration.stopWords"/></th>
+                                               <f:if condition="{title}=='words'">
+                                                       <f:if condition="{page}">
+                                                               <th><f:translate key="administration.keywords"/></th>
+                                                       </f:if>
+                                               </f:if>
+                                               <th><f:translate key="administration.statistics.word"/></th>
+                                               <th><f:translate key="field.wordCount"/></th>
+                                               <th><f:translate key="field.frequency"/></th>
+                                               <th><f:translate key="field.flag"/></th>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{words}" as="word">
+                                               <tr>
+                                                       <td>
+                                                               <f:form.checkbox name="stopwords[{word.wid}]" value="1" checked="{word.is_stopword}"/>
+                                                       </td>
+                                                       <f:if condition="{title}=='words'">
+                                                               <f:if condition="{page}">
+                                                                       <td>
+                                                                               <f:form.checkbox name="keywords[{word.baseword}]" value="1" checked="{word.is_keyword}"/>
+                                                                       </td>
+                                                               </f:if>
+                                                       </f:if>
+                                                       <td>
+                                                               <f:link.action action="wordDetail" arguments="{id:word.wid,pageHash:phash}">{word.baseword}</f:link.action>
+                                                       </td>
+                                                       <td>{word.count}</td>
+                                                       <td>{word.freq}</td>
+                                                       <td>
+                                                               <f:if condition="{word.flags} > 0">
+                                                                       {is:format.flagValue(flags:word.flags)} ({word.flags})
+                                                               </f:if>
+                                                       </td>
+                                               </tr>
+                                       </f:for>
+                               </tbody>
+                       </table>
+                       <f:if condition="{title}=='words'">
+                               <f:then>
+                                       <f:if condition="{keywords}">
+                                               <div>
+                                                       {f:translate(key:'administration.keywords.current')}:
+                                                       <f:for each="{keywords}" key="keyword" as="_" iteration="i">
+                                                               {f:if(condition:i.isFirst,then:'',else:', ')}<i>{keyword}</i>
+                                                       </f:for>
+                                               </div>
+                                       </f:if>
+                                       <f:form.submit value="{f:translate(key:'administration.stopWordsKeywords.save')}"/>
+                               </f:then>
+                               <f:else>
+                                       <f:form.submit value="{f:translate(key:'administration.stopWords.save')}"/>
+                               </f:else>
+
+                       </f:if>
+
+               </f:form>
+       </f:if>
+</f:section>
+
+<f:section name="Buttons">
+       <f:be.buttons.icon title="{f:translate(key:'administration.back')}" icon="actions-view-go-back" uri="{f:uri.action(action:'statistic')}"/>
+</f:section>
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/WordDetail.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Administration/WordDetail.html
new file mode 100644 (file)
index 0000000..9c3707a
--- /dev/null
@@ -0,0 +1,51 @@
+<f:layout name="Administration"/>
+
+<f:section name="Content">
+       <p class="lead">
+               <f:translate key="administration.word.description"/>
+       </p>
+       <f:if condition="{rows}">
+               <f:then>
+                       <table class="t3-table">
+                               <thead>
+                                       <tr>
+                                               <th><f:translate key="field.pHash"/></th>
+                                               <th><f:translate key="field.id"/></th>
+                                               <th><f:translate key="field.fileName"/></th>
+                                               <th><f:translate key="field.count"/></th>
+                                               <th><f:translate key="field.first"/></th>
+                                               <th><f:translate key="field.frequency"/></th>
+                                               <th><f:translate key="field.flag"/></th>
+                                       </tr>
+                               </thead>
+                               <tbody>
+                                       <f:for each="{rows}" as="row">
+                                               <tr>
+                                                       <td>
+                                                               <f:link.action action="statisticDetails" arguments="{pageHash:row.phash}">{row.phash}</f:link.action>
+                                                       </td>
+                                                       <td>{row.page_id}</td>
+                                                       <td>{row.data_filename}</td>
+                                                       <td>{row.count}</td>
+                                                       <td>{row.first}</td>
+                                                       <td>{row.freq}</td>
+                                                       <td>{row.flags}</td>
+                                               </tr>
+                                       </f:for>
+                               </tbody>
+                       </table>
+               </f:then>
+               <f:else>
+                       <div class="typo3-message message-error">
+                               <div class="message-body">
+                                       <f:translate key="administration.statistics.noResult"/>
+                               </div>
+                       </div>
+               </f:else>
+       </f:if>
+       <f:link.action action="statisticDetails" arguments="{pageHash:phash}">
+               <f:translate key="administration.linkBack"/>
+       </f:link.action>
+</f:section>
+
+<f:section name="Buttons"></f:section>
\ No newline at end of file
index 388c751..a783ecd 100644 (file)
@@ -41,4 +41,4 @@ $_EXTCONF = unserialize($_EXTCONF);
 // Use the advanced doubleMetaphone parser instead of the internal one (usage of metaphone parsers is generally disabled by default)
 if (isset($_EXTCONF['enableMetaphoneSearch']) && (int)$_EXTCONF['enableMetaphoneSearch'] == 2) {
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['metaphone'] = '&TYPO3\\CMS\\IndexedSearch\\Utility\\DoubleMetaPhoneUtility';
-}
+}
\ No newline at end of file
index b7ce5d3..c10e77f 100644 (file)
@@ -21,8 +21,24 @@ if (TYPO3_MODE === 'BE') {
                'LLL:EXT:indexed_search/locallang.xlf:mod2_indexed_search'
        );
 
-       $GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses']['tx_indexed_search_pi_wizicon'] =
-               \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'pi/class.tx_indexed_search_pi_wizicon.php';
+       \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+               'TYPO3.CMS.IndexedSearch',
+               'web',
+               'isearch',
+               '',
+               array(
+                       'Administration' => 'index,pages,externalDocuments,statistic,statisticDetails,deleteIndexedItem,saveStopwordsKeywords,wordDetail',
+               ),
+               array(
+                       'access' => 'admin',
+                       'icon'   => 'EXT:indexed_search/Resources/Public/Icons/module-indexed_search.png',
+                       'labels' => 'LLL:EXT:indexed_search/mod/locallang_mod.xlf',
+               )
+       );
 }
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript', 'IndexedSearch');
+
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('index_config');
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('index_config', 'EXT:indexed_search/locallang_csh_indexcfg.xlf');
\ No newline at end of file
index 82739cb..74f9dd8 100644 (file)
                        <trans-unit id="allpages" xml:space="preserve">
                                <source>Statistics for all pages. Select a page with indexed search form to see several statistics</source>
                        </trans-unit>
+                       <trans-unit id="word" xml:space="preserve">
+                               <source>Word</source>
+                       </trans-unit>
+                       <trans-unit id="count" xml:space="preserve">
+                               <source>Count</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>