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\Type\Bitmask\Permission
;
29 use TYPO3\CMS\Core\Utility\GeneralUtility
;
30 use TYPO3\CMS\IndexedSearch\FileContentParser
;
33 * Administration repository
35 class AdministrationRepository
38 * List of fileContentParsers
40 * @var FileContentParser[]
42 public $external_parsers = [];
47 protected $allPhashListed = [];
52 protected $iconFileNameCache = [];
55 * Get group list information
60 public function getGrlistRecord($phash)
62 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_grlist');
63 $result = $queryBuilder
65 ->from('index_grlist')
67 $queryBuilder->expr()->eq(
69 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
73 $numberOfRows = $result->rowCount();
75 while ($row = $result->fetch()) {
76 $row['pcount'] = $numberOfRows;
83 * Get number of fulltext records
88 public function getNumberOfFulltextRecords($phash)
90 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_fulltext');
93 ->from('index_fulltext')
95 $queryBuilder->expr()->eq(
97 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
105 * Get number of words
110 public function getNumberOfWords($phash)
112 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_rel');
117 $queryBuilder->expr()->eq(
119 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
127 * Get statistic of external documents
131 public function getExternalDocumentsStatistic()
135 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
137 ->select('index_phash.*')
138 ->addSelectLiteral($queryBuilder->expr()->count('*', 'pcount'))
139 ->from('index_phash')
140 ->where($queryBuilder->expr()->neq('item_type', $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)))
167 ->orderBy('item_type')
170 while ($row = $res->fetch()) {
171 $this->addAdditionalInformation($row);
175 if ($row['pcount'] > 1) {
176 $res2 = $queryBuilder
178 ->from('index_phash')
180 $queryBuilder->expr()->eq(
182 $queryBuilder->createNamedParameter($row['phash_grouping'], \PDO
::PARAM_INT
)
184 $queryBuilder->expr()->neq(
186 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
190 while ($row2 = $res2->fetch()) {
191 $this->addAdditionalInformation($row2);
200 * Get count of the tables used for indexed_search
204 public function getRecordsNumbers()
215 foreach ($tables as $tableName) {
216 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable($tableName);
217 $recordList[$tableName] = $queryBuilder
231 public function getPageHashTypes()
241 $revTypes = array_flip($types);
242 $revTypes[0] = 'TYPO3 page';
244 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
246 ->select('item_type')
247 ->addSelectLiteral($queryBuilder->expr()->count('*', 'count'))
248 ->from('index_phash')
249 ->groupBy('item_type')
250 ->orderBy('item_type')
253 while ($row = $res->fetch()) {
254 $itemType = $row['item_type'];
256 'count' => $row['count'],
257 'name' => $revTypes[$itemType],
259 'uniqueCount' => $this->countUniqueTypes($itemType),
268 * @param string $itemType
271 protected function countUniqueTypes($itemType)
273 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
274 $items = $queryBuilder
276 ->from('index_phash')
278 $queryBuilder->expr()->eq(
280 $queryBuilder->createNamedParameter($itemType, \PDO
::PARAM_STR
)
283 ->groupBy('phash_grouping')
287 return count($items);
291 * Get number of section records
293 * @param int $pageHash
296 public function getNumberOfSections($pageHash)
298 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_section');
299 return (int)$queryBuilder
301 ->from('index_section')
303 $queryBuilder->expr()->eq(
305 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
317 public function getPageStatistic()
320 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
322 ->select('index_phash.*')
323 ->addSelectLiteral($queryBuilder->expr()->count('*', 'pcount'))
324 ->from('index_phash')
325 ->where($queryBuilder->expr()->neq('data_page_id', $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)))
352 ->orderBy('data_page_id')
355 while ($row = $res->fetch()) {
356 $this->addAdditionalInformation($row);
359 if ($row['pcount'] > 1) {
360 $res2 = $queryBuilder
362 ->from('index_phash')
364 $queryBuilder->expr()->eq(
366 $queryBuilder->createNamedParameter($row['phash_grouping'], \PDO
::PARAM_INT
)
368 $queryBuilder->expr()->neq(
370 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
374 while ($row2 = $res2->fetch()) {
375 $this->addAdditionalInformation($row2);
384 * Get general statistic
386 * @param string $additionalWhere
387 * @param int $pageUid
391 public function getGeneralSearchStatistic($additionalWhere, $pageUid, $max = 50)
393 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
394 ->getQueryBuilderForTable('index_stat_word');
397 ->from('index_stat_word')
398 ->addSelectLiteral($queryBuilder->expr()->count('*', 'c'))
400 $queryBuilder->expr()->eq(
402 $queryBuilder->createNamedParameter($pageUid, \PDO
::PARAM_INT
)
406 ->setMaxResults((int)$max);
408 if (!empty($additionalWhere)) {
409 $queryBuilder->andWhere(QueryHelper
::stripLogicalOperatorPrefix($additionalWhere));
412 $result = $queryBuilder->execute();
413 $count = (int)$result->rowCount();
414 $result->closeCursor();
416 // exist several statistics for this page?
418 // Limit access to pages of the current site
419 $queryBuilder->where(
420 $queryBuilder->expr()->in(
422 $queryBuilder->createNamedParameter(
423 GeneralUtility
::intExplode(',', $this->extGetTreeList((int)$pageUid, 100, 0, '1=1'), true),
424 Connection
::PARAM_INT_ARRAY
427 QueryHelper
::stripLogicalOperatorPrefix($additionalWhere)
431 return $queryBuilder->execute()->fetchAll();
435 * Add additional information to the result row
439 protected function addAdditionalInformation(array &$row)
441 $grListRec = $this->getGrlistRecord($row['phash']);
442 $unserializedCHashParams = unserialize($row['cHashParams']);
444 $row['numberOfWords'] = $this->getNumberOfWords($row['phash']);
445 $row['numberOfSections'] = $this->getNumberOfSections($row['phash']);
446 $row['numberOfFulltext'] = $this->getNumberOfFulltextRecords($row['phash']);
447 $row['cHashParams'] = !empty($unserializedCHashParams) ?
$unserializedCHashParams : '';
448 $row['grList'] = $grListRec;
452 * Get the page tree by using \TYPO3\CMS\Backend\Tree\View\PageTreeView
456 * @param string $mode
459 public function getTree($pageId, $depth = 4, $mode)
462 $pageRecord = BackendUtility
::getRecord('pages', (int)$pageId);
466 /** @var PageTreeView $tree */
467 $tree = GeneralUtility
::makeInstance(PageTreeView
::class);
468 $perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(Permission
::PAGE_SHOW
);
469 $tree->init('AND ' . $perms_clause);
470 $iconFactory = GeneralUtility
::makeInstance(IconFactory
::class);
471 $HTML = '<span title="' . htmlspecialchars($pageRecord['title']) . '">' . $iconFactory->getIconForRecord('pages', $pageRecord, Icon
::SIZE_SMALL
)->render() . '</span>';
473 'row' => $pageRecord,
478 $tree->getTree((int)$pageId, $depth, '');
481 foreach ($tree->tree
as $singleLine) {
482 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
483 $result = $queryBuilder->select(
501 'IP.item_description',
508 'IP.sys_language_uid',
515 ->addSelectLiteral($queryBuilder->expr()->count('*', 'count_val'))
516 ->from('index_phash', 'IP')
517 ->from('index_section', 'ISEC')
519 $queryBuilder->expr()->eq('IP.phash', $queryBuilder->quoteIdentifier('ISEC.phash')),
520 $queryBuilder->expr()->eq(
522 $queryBuilder->createNamedParameter($singleLine['row']['uid'], \PDO
::PARAM_INT
)
537 'IP.item_description',
544 'IP.sys_language_uid',
558 ->orderBy('IP.item_type')
559 ->addOrderBy('IP.tstamp')
564 // Collecting phash values (to remove local indexing for)
565 // Traverse the result set of phash rows selected:
566 while ($row = $result->fetch()) {
567 $row['icon'] = $this->makeItemTypeIcon($row['item_type']);
568 $this->allPhashListed
[] = $row['phash'];
570 // Adds a display row:
571 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
572 ->getQueryBuilderForTable('index_rel');
573 $wordCountResult = $queryBuilder->count('index_words.baseword')
575 ->from('index_words')
577 $queryBuilder->expr()->eq(
579 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
581 $queryBuilder->expr()->eq('index_words.wid', $queryBuilder->quoteIdentifier('index_rel.wid'))
583 ->groupBy('index_words.baseword')
586 $row['wordCount'] = $wordCountResult->rowCount();
587 $wordCountResult->closeCursor();
589 if ($mode === 'content') {
590 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
591 ->getQueryBuilderForTable('index_fulltext');
592 $row['fulltextData'] = $queryBuilder->select('*')
593 ->from('index_fulltext')
595 $queryBuilder->expr()->eq(
597 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
604 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
605 ->getQueryBuilderForTable('index_rel');
606 $wordRecords = $queryBuilder->select('index_words.baseword')
608 ->from('index_words')
610 $queryBuilder->expr()->eq(
612 $queryBuilder->createNamedParameter($row['phash'], \PDO
::PARAM_INT
)
614 $queryBuilder->expr()->eq(
616 $queryBuilder->quoteIdentifier('index_rel.wid')
619 ->groupBy('index_words.baseword')
620 ->orderBy('index_words.baseword')
624 if (is_array($wordRecords)) {
625 $row['allWords'] = array_column($wordRecords, 'baseword');
632 $singleLine['lines'] = $lines;
633 $allLines[] = $singleLine;
640 * Generates a list of Page-uid's from $id.
641 * The only pages excluded from the list are deleted pages.
643 * @param int $id page id
644 * @param int $depth to traverse down the page tree.
645 * @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'
646 * @param string $perms_clause
647 * @return string Returns the list with a comma in the end + id itself
649 protected function extGetTreeList($id, $depth, $begin = 0, $perms_clause)
651 $list = GeneralUtility
::makeInstance(FrontendBackendUserAuthentication
::class)
652 ->extGetTreeList($id, $depth, $begin, $perms_clause);
657 $list = rtrim($list, ',') . ',' . $id;
664 * Remove indexed phash row
666 * @param string $phashList
670 public function removeIndexedPhashRow($phashList, $pageId, $depth = 4)
672 if ($phashList === 'ALL') {
673 $this->getTree($pageId, $depth, '');
674 $phashRows = $this->allPhashListed
;
675 $this->allPhashListed
= [];
677 $phashRows = GeneralUtility
::trimExplode(',', $phashList, true);
680 foreach ($phashRows as $phash) {
681 $phash = (int)$phash;
684 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
685 ->getQueryBuilderForTable('index_section');
688 ->from('index_section')
690 $queryBuilder->expr()->eq(
692 $queryBuilder->createNamedParameter($phash, \PDO
::PARAM_INT
)
696 while ($row = $res->fetch()) {
697 $idList[] = (int)$row['page_id'];
700 if (!empty($idList)) {
701 /** @var FrontendInterface $pageCache */
702 $pageCache = GeneralUtility
::makeInstance(CacheManager
::class)->getCache('cache_pages');
703 foreach ($idList as $pageId) {
704 $pageCache->flushByTag('pageId_' . $pageId);
708 // Removing old registrations for all tables.
717 foreach ($tableArr as $table) {
718 GeneralUtility
::makeInstance(ConnectionPool
::class)
719 ->getConnectionForTable($table)
720 ->delete($table, ['phash' => (int)$phash]);
729 * @param array $words stop words
731 public function saveStopWords(array $words)
733 foreach ($words as $wid => $state) {
734 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_words');
736 ->update('index_words')
737 ->set('is_stopword', (int)$state)
739 $queryBuilder->expr()->eq(
741 $queryBuilder->createNamedParameter($wid, \PDO
::PARAM_INT
)
751 * @param array $words keywords
752 * @param int $pageId page id
754 public function saveKeywords(array $words, $pageId)
756 // Get pages current keywords
757 $pageRec = BackendUtility
::getRecord('pages', $pageId);
758 if (!is_array($pageRec)) {
761 $keywords = array_flip(GeneralUtility
::trimExplode(',', $pageRec['keywords'], true));
763 foreach ($words as $key => $v) {
767 unset($keywords[$key]);
772 $data['pages'][$pageId]['keywords'] = implode(', ', array_keys($keywords));
773 $dataHandler = GeneralUtility
::makeInstance(DataHandler
::class);
774 $dataHandler->start($data, []);
775 $dataHandler->process_datamap();
779 * Collect the type icons
781 * @param string $itemType
784 protected function makeItemTypeIcon($itemType)
786 if (!isset($this->iconFileNameCache
[$itemType])) {
788 if ($itemType === '0') {
789 $icon = 'EXT:indexed_search/Resources/Public/Icons/FileTypes/pages.gif';
790 } elseif ($this->external_parsers
[$itemType]) {
791 $icon = $this->external_parsers
[$itemType]->getIcon($itemType);
793 $this->iconFileNameCache
[$itemType] = $icon;
795 return $this->iconFileNameCache
[$itemType];
799 * @return BackendUserAuthentication
801 protected function getBackendUserAuthentication()
803 return $GLOBALS['BE_USER'];