2 namespace TYPO3\CMS\IndexedSearch\Domain\Repository
;
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
16 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication
;
17 use TYPO3\CMS\Backend\Tree\View\PageTreeView
;
18 use TYPO3\CMS\Backend\Utility\BackendUtility
;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication
;
20 use TYPO3\CMS\Core\Cache\CacheManager
;
21 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
;
22 use TYPO3\CMS\Core\Database\Connection
;
23 use TYPO3\CMS\Core\Database\ConnectionPool
;
24 use TYPO3\CMS\Core\Database\Query\QueryHelper
;
25 use TYPO3\CMS\Core\DataHandling\DataHandler
;
26 use TYPO3\CMS\Core\Imaging\Icon
;
27 use TYPO3\CMS\Core\Imaging\IconFactory
;
28 use TYPO3\CMS\Core\Utility\GeneralUtility
;
29 use TYPO3\CMS\IndexedSearch\FileContentParser
;
32 * Administration repository
34 class AdministrationRepository
37 * List of fileContentParsers
39 * @var FileContentParser[]
41 public $external_parsers = [];
46 protected $allPhashListed = [];
51 protected $iconFileNameCache = [];
54 * Get group list information
59 public function getGrlistRecord($phash)
61 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_grlist');
62 $result = $queryBuilder
64 ->from('index_grlist')
66 $queryBuilder->expr()->eq(
68 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
72 $numberOfRows = $result->rowCount();
74 while ($row = $result->fetch()) {
75 $row['pcount'] = $numberOfRows;
82 * Get number of fulltext records
87 public function getNumberOfFulltextRecords($phash)
89 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_fulltext');
92 ->from('index_fulltext')
94 $queryBuilder->expr()->eq(
96 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
104 * Get number of words
109 public function getNumberOfWords($phash)
111 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_rel');
116 $queryBuilder->expr()->eq(
118 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
126 * Get statistic of external documents
130 public function getExternalDocumentsStatistic()
134 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
136 ->select('index_phash.*')
137 ->addSelectLiteral($queryBuilder->expr()->count('*', 'pcount'))
138 ->from('index_phash')
139 ->where($queryBuilder->expr()->neq('item_type', $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)))
166 ->orderBy('item_type')
169 while ($row = $res->fetch()) {
170 $this->addAdditionalInformation($row);
174 if ($row['pcount'] > 1) {
175 $res2 = $queryBuilder
177 ->from('index_phash')
179 $queryBuilder->expr()->eq(
181 $queryBuilder->createNamedParameter($row['phash_grouping'], \PDO
::PARAM_INT
)
183 $queryBuilder->expr()->neq(
185 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
189 while ($row2 = $res2->fetch()) {
190 $this->addAdditionalInformation($row2);
199 * Get count of the tables used for indexed_search
203 public function getRecordsNumbers()
214 foreach ($tables as $tableName) {
215 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable($tableName);
216 $recordList[$tableName] = $queryBuilder
230 public function getPageHashTypes()
240 $revTypes = array_flip($types);
241 $revTypes[0] = 'TYPO3 page';
243 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
245 ->select('item_type')
246 ->addSelectLiteral($queryBuilder->expr()->count('*', 'count'))
247 ->from('index_phash')
248 ->groupBy('item_type')
249 ->orderBy('item_type')
252 while ($row = $res->fetch()) {
253 $itemType = $row['item_type'];
255 'count' => $row['count'],
256 'name' => $revTypes[$itemType],
258 'uniqueCount' => $this->countUniqueTypes($itemType),
267 * @param string $itemType
270 protected function countUniqueTypes($itemType)
272 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
273 $items = $queryBuilder
275 ->from('index_phash')
277 $queryBuilder->expr()->eq(
279 $queryBuilder->createNamedParameter($itemType, \PDO
::PARAM_STR
)
282 ->groupBy('phash_grouping')
286 return count($items);
290 * Get number of section records
292 * @param int $pageHash
295 public function getNumberOfSections($pageHash)
297 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_section');
298 return (int)$queryBuilder
300 ->from('index_section')
302 $queryBuilder->expr()->eq(
304 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
316 public function getPageStatistic()
319 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
321 ->select('index_phash.*')
322 ->addSelectLiteral($queryBuilder->expr()->count('*', 'pcount'))
323 ->from('index_phash')
324 ->where($queryBuilder->expr()->neq('data_page_id', $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)))
351 ->orderBy('data_page_id')
354 while ($row = $res->fetch()) {
355 $this->addAdditionalInformation($row);
358 if ($row['pcount'] > 1) {
359 $res2 = $queryBuilder
361 ->from('index_phash')
363 $queryBuilder->expr()->eq(
365 $queryBuilder->createNamedParameter($row['phash_grouping'], \PDO
::PARAM_INT
)
367 $queryBuilder->expr()->neq(
369 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
373 while ($row2 = $res2->fetch()) {
374 $this->addAdditionalInformation($row2);
383 * Get general statistic
385 * @param string $additionalWhere
386 * @param int $pageUid
390 public function getGeneralSearchStatistic($additionalWhere, $pageUid, $max = 50)
392 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
393 ->getQueryBuilderForTable('index_stat_word');
396 ->from('index_stat_word')
397 ->addSelectLiteral($queryBuilder->expr()->count('*', 'c'))
399 $queryBuilder->expr()->eq(
401 $queryBuilder->createNamedParameter($pageUid, \PDO
::PARAM_INT
)
405 ->setMaxResults((int)$max);
407 if (!empty($additionalWhere)) {
408 $queryBuilder->andWhere(QueryHelper
::stripLogicalOperatorPrefix($additionalWhere));
411 $result = $queryBuilder->execute();
412 $count = (int)$result->rowCount();
413 $result->closeCursor();
415 // exist several statistics for this page?
417 // Limit access to pages of the current site
418 $queryBuilder->where(
419 $queryBuilder->expr()->in(
421 $queryBuilder->createNamedParameter(
422 GeneralUtility
::intExplode(',', $this->extGetTreeList((int)$pageUid, 100, 0, '1=1'), true
),
423 Connection
::PARAM_INT_ARRAY
426 QueryHelper
::stripLogicalOperatorPrefix($additionalWhere)
430 return $queryBuilder->execute()->fetchAll();
434 * Add additional information to the result row
438 protected function addAdditionalInformation(array &$row)
440 $grListRec = $this->getGrlistRecord($row['phash']);
441 $unserializedCHashParams = unserialize($row['cHashParams']);
443 $row['numberOfWords'] = $this->getNumberOfWords($row['phash']);
444 $row['numberOfSections'] = $this->getNumberOfSections($row['phash']);
445 $row['numberOfFulltext'] = $this->getNumberOfFulltextRecords($row['phash']);
446 $row['cHashParams'] = !empty($unserializedCHashParams) ?
$unserializedCHashParams : '';
447 $row['grList'] = $grListRec;
451 * Get the page tree by using \TYPO3\CMS\Backend\Tree\View\PageTreeView
455 * @param string $mode
458 public function getTree($pageId, $depth = 4, $mode)
461 $pageRecord = BackendUtility
::getRecord('pages', (int)$pageId);
465 /** @var PageTreeView $tree */
466 $tree = GeneralUtility
::makeInstance(PageTreeView
::class);
467 $perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
468 $tree->init('AND ' . $perms_clause);
469 $iconFactory = GeneralUtility
::makeInstance(IconFactory
::class);
470 $HTML = '<span title="' . htmlspecialchars($pageRecord['title']) . '">' . $iconFactory->getIconForRecord('pages', $pageRecord, Icon
::SIZE_SMALL
)->render() . '</span>';
472 'row' => $pageRecord,
477 $tree->getTree((int)$pageId, $depth, '');
480 foreach ($tree->tree
as $singleLine) {
481 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
482 $result = $queryBuilder->select(
500 'IP.item_description',
507 'IP.sys_language_uid',
514 ->addSelectLiteral($queryBuilder->expr()->count('*', 'count_val'))
515 ->from('index_phash', 'IP')
516 ->from('index_section', 'ISEC')
518 $queryBuilder->expr()->eq('IP.phash', $queryBuilder->quoteIdentifier('ISEC.phash')),
519 $queryBuilder->expr()->eq(
521 $queryBuilder->createNamedParameter($singleLine['row']['uid'], \PDO
::PARAM_INT
)
536 'IP.item_description',
543 'IP.sys_language_uid',
557 ->orderBy('IP.item_type')
558 ->addOrderBy('IP.tstamp')
563 // Collecting phash values (to remove local indexing for)
564 // Traverse the result set of phash rows selected:
565 while ($row = $result->fetch()) {
566 $row['icon'] = $this->makeItemTypeIcon($row['item_type']);
567 $this->allPhashListed
[] = $row['phash'];
569 // Adds a display row:
570 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
571 ->getQueryBuilderForTable('index_rel');
572 $wordCountResult = $queryBuilder->count('index_words.baseword')
574 ->from('index_words')
576 $queryBuilder->expr()->eq(
578 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
580 $queryBuilder->expr()->eq('index_words.wid', $queryBuilder->quoteIdentifier('index_rel.wid'))
582 ->groupBy('index_words.baseword')
585 $row['wordCount'] = $wordCountResult->rowCount();
586 $wordCountResult->closeCursor();
588 if ($mode === 'content') {
589 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
590 ->getQueryBuilderForTable('index_fulltext');
591 $row['fulltextData'] = $queryBuilder->select('*')
592 ->from('index_fulltext')
594 $queryBuilder->expr()->eq(
596 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
603 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
604 ->getQueryBuilderForTable('index_rel');
605 $wordRecords = $queryBuilder->select('index_words.baseword')
607 ->from('index_words')
609 $queryBuilder->expr()->eq(
611 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
613 $queryBuilder->expr()->eq(
615 $queryBuilder->quoteIdentifier('index_rel.wid')
618 ->groupBy('index_words.baseword')
619 ->orderBy('index_words.baseword')
623 if (is_array($wordRecords)) {
624 $row['allWords'] = array_column($wordRecords, 'baseword');
631 $singleLine['lines'] = $lines;
632 $allLines[] = $singleLine;
639 * Generates a list of Page-uid's from $id.
640 * The only pages excluded from the list are deleted pages.
642 * @param int $id page id
643 * @param int $depth to traverse down the page tree.
644 * @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'
645 * @param string $perms_clause
646 * @return string Returns the list with a comma in the end + id itself
648 protected function extGetTreeList($id, $depth, $begin = 0, $perms_clause)
650 $list = GeneralUtility
::makeInstance(FrontendBackendUserAuthentication
::class)
651 ->extGetTreeList($id, $depth, $begin, $perms_clause);
656 $list = rtrim($list, ',') . ',' . $id;
663 * Remove indexed phash row
665 * @param string $phashList
669 public function removeIndexedPhashRow($phashList, $pageId, $depth = 4)
671 if ($phashList === 'ALL') {
672 $this->getTree($pageId, $depth, '');
673 $phashRows = $this->allPhashListed
;
674 $this->allPhashListed
= [];
676 $phashRows = GeneralUtility
::trimExplode(',', $phashList, true
);
679 foreach ($phashRows as $phash) {
680 $phash = (int)$phash;
683 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
684 ->getQueryBuilderForTable('index_section');
687 ->from('index_section')
689 $queryBuilder->expr()->eq(
691 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
695 while ($row = $res->fetch()) {
696 $idList[] = (int)$row['page_id'];
699 if (!empty($idList)) {
700 /** @var FrontendInterface $pageCache */
701 $pageCache = GeneralUtility
::makeInstance(CacheManager
::class)->getCache('cache_pages');
702 foreach ($idList as $pageId) {
703 $pageCache->flushByTag('pageId_' . $pageId);
707 // Removing old registrations for all tables.
716 foreach ($tableArr as $table) {
717 GeneralUtility
::makeInstance(ConnectionPool
::class)
718 ->getConnectionForTable($table)
719 ->delete($table, ['phash' => (int)$phash]);
728 * @param array $words stop words
730 public function saveStopWords(array $words)
732 foreach ($words as $wid => $state) {
733 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_words');
735 ->update('index_words')
736 ->set('is_stopword', (int)$state)
738 $queryBuilder->expr()->eq(
740 $queryBuilder->createNamedParameter($wid, \PDO
::PARAM_INT
)
750 * @param array $words keywords
751 * @param int $pageId page id
753 public function saveKeywords(array $words, $pageId)
755 // Get pages current keywords
756 $pageRec = BackendUtility
::getRecord('pages', $pageId);
757 if (!is_array($pageRec)) {
760 $keywords = array_flip(GeneralUtility
::trimExplode(',', $pageRec['keywords'], true
));
762 foreach ($words as $key => $v) {
766 unset($keywords[$key]);
771 $data['pages'][$pageId]['keywords'] = implode(', ', array_keys($keywords));
772 $dataHandler = GeneralUtility
::makeInstance(DataHandler
::class);
773 $dataHandler->start($data, []);
774 $dataHandler->process_datamap();
778 * Collect the type icons
780 * @param string $itemType
783 protected function makeItemTypeIcon($itemType)
785 if (!isset($this->iconFileNameCache
[$itemType])) {
787 if ($itemType === '0') {
788 $icon = 'EXT:indexed_search/Resources/Public/Icons/FileTypes/pages.gif';
789 } elseif ($this->external_parsers
[$itemType]) {
790 $icon = $this->external_parsers
[$itemType]->getIcon($itemType);
792 $this->iconFileNameCache
[$itemType] = $icon;
794 return $this->iconFileNameCache
[$itemType];
798 * @return BackendUserAuthentication
800 protected function getBackendUserAuthentication()
802 return $GLOBALS['BE_USER'];