diff --git a/Classes/Controller/Backend/Search/InfoModuleController.php b/Classes/Controller/Backend/Search/InfoModuleController.php
index 01acdf5c48..93cbf63c74 100644
--- a/Classes/Controller/Backend/Search/InfoModuleController.php
+++ b/Classes/Controller/Backend/Search/InfoModuleController.php
@@ -17,6 +17,7 @@
use ApacheSolrForTypo3\Solr\Api;
use ApacheSolrForTypo3\Solr\Domain\Search\ApacheSolrDocument\Repository as ApacheSolrDocumentRepository;
+use ApacheSolrForTypo3\Solr\Domain\Search\Statistics\StatisticsFilterDto;
use ApacheSolrForTypo3\Solr\Domain\Search\Statistics\StatisticsRepository;
use ApacheSolrForTypo3\Solr\System\Solr\ResponseAdapter;
use ApacheSolrForTypo3\Solr\System\Validator\Path;
@@ -49,15 +50,21 @@ protected function initializeAction()
*
* @return ResponseInterface
*/
- public function indexAction(): ResponseInterface
- {
+ public function indexAction(
+ ?StatisticsFilterDto $statisticsFilter = null,
+ int $activeTabId = 0,
+ string $operation = ''
+ ): ResponseInterface {
+ $this->initializeAction();
+
+ $this->view->assign('activeTabId', $activeTabId);
if ($this->selectedSite === null) {
$this->view->assign('can_not_proceed', true);
return $this->getModuleTemplateResponse();
}
$this->collectConnectionInfos();
- $this->collectStatistics();
+ $this->collectStatistics($statisticsFilter, $operation);
$this->collectIndexFieldsInfo();
$this->collectIndexInspectorInfo();
@@ -129,37 +136,39 @@ protected function collectConnectionInfos(): void
/**
* Index action, shows an overview of the state of the Solr index
*/
- protected function collectStatistics(): void
+ protected function collectStatistics(?StatisticsFilterDto $statisticsFilterDto, string $operation): void
{
// TODO make time frame user adjustable, for now it's last 30 days
+ $statisticsFilter = $this->getStatisticsFilter($statisticsFilterDto, $operation);
- $siteRootPageId = $this->selectedSite->getRootPageId();
- /* @var StatisticsRepository $statisticsRepository */
+ /** @var StatisticsRepository $statisticsRepository */
$statisticsRepository = GeneralUtility::makeInstance(StatisticsRepository::class);
// @TODO: Do we want Typoscript constants to restrict the results?
$this->view->assign(
'top_search_phrases',
- $statisticsRepository->getTopKeyWordsWithHits($siteRootPageId, 30, 5)
+ $statisticsRepository->getTopKeyWordsWithHits($statisticsFilter)
);
$this->view->assign(
'top_search_phrases_without_hits',
- $statisticsRepository->getTopKeyWordsWithoutHits($siteRootPageId, 30, 5)
+ $statisticsRepository->getTopKeyWordsWithoutHits($statisticsFilter)
);
$this->view->assign(
'search_phrases_statistics',
- $statisticsRepository->getSearchStatistics($siteRootPageId, 30, 100)
+ $statisticsRepository->getSearchStatistics($statisticsFilter)
);
$labels = [];
$data = [];
- $chartData = $statisticsRepository->getQueriesOverTime($siteRootPageId, 30, 86400);
+ $chartData = $statisticsRepository->getQueriesOverTime($statisticsFilter, 86400);
+
foreach ($chartData as $bucket) {
// @todo Replace deprecated strftime in php 8.1. Suppress warning for now
$labels[] = @strftime('%x', $bucket['timestamp']);
$data[] = (int)$bucket['numQueries'];
}
+ $this->view->assign('statisticsFilter', $statisticsFilter);
$this->view->assign('queriesChartLabels', json_encode($labels));
$this->view->assign('queriesChartData', json_encode($data));
}
@@ -294,4 +303,13 @@ protected function getCoreMetrics(ResponseAdapter $lukeData, array $fields): arr
'numberOfFields' => count($fields),
];
}
+
+ protected function getStatisticsFilter(?StatisticsFilterDto $statisticsFilterDto, string $operation): StatisticsFilterDto
+ {
+ if ($statisticsFilterDto === null || $operation === 'reset-filters') {
+ $statisticsFilterDto = GeneralUtility::makeInstance(StatisticsFilterDto::class);
+ }
+
+ return $statisticsFilterDto->setSiteRootPageId($this->selectedSite->getRootPageId());
+ }
}
diff --git a/Classes/Domain/Search/Statistics/StatisticsFilterDto.php b/Classes/Domain/Search/Statistics/StatisticsFilterDto.php
new file mode 100644
index 0000000000..96c2dfe39c
--- /dev/null
+++ b/Classes/Domain/Search/Statistics/StatisticsFilterDto.php
@@ -0,0 +1,137 @@
+startDate = DateTime::createFromFormat('U', (string)$this->getQueriesStartDate());
+ $this->endDate = DateTime::createFromFormat('U', (string)$this->getEndDateTimestamp());
+ }
+
+ public function setSiteRootPageId(int $siteRootPageId): StatisticsFilterDto
+ {
+ $this->siteRootPageId = $siteRootPageId;
+ return $this;
+ }
+
+ public function setStartDate(?DateTime $startDate): StatisticsFilterDto
+ {
+ $this->startDate = $startDate;
+ return $this;
+ }
+
+ public function setEndDate(?DateTime $endDate): StatisticsFilterDto
+ {
+ $this->endDate = $endDate;
+ return $this;
+ }
+
+ public function getTopHitsDays(): int
+ {
+ return $this->topHitsDays;
+ }
+
+ public function getNoHitsDays(): int
+ {
+ return $this->noHitsDays;
+ }
+
+ public function getQueriesDays(): int
+ {
+ return $this->queriesDays;
+ }
+
+ public function getSiteRootPageId(): int
+ {
+ return $this->siteRootPageId;
+ }
+
+ public function getTopHitsLimit(): int
+ {
+ return $this->topHitsLimit;
+ }
+
+ public function getNoHitsLimit(): int
+ {
+ return $this->noHitsLimit;
+ }
+
+ public function getQueriesLimit(): int
+ {
+ return $this->queriesLimit;
+ }
+
+ public function getStartDate(): ?DateTime
+ {
+ return $this->startDate;
+ }
+
+ public function getEndDate(): ?DateTime
+ {
+ return $this->endDate;
+ }
+
+ public function getTopHitsStartDate(): int
+ {
+ if ($this->startDate !== null) {
+ return $this->startDate->getTimestamp();
+ }
+
+ return $this->getTimeStampSinceDays($this->topHitsDays);
+ }
+
+ public function getNoHitsStartDate(): int
+ {
+ if ($this->startDate !== null) {
+ return $this->startDate->getTimestamp();
+ }
+
+ return $this->getTimeStampSinceDays($this->noHitsDays);
+ }
+
+ public function getQueriesStartDate(): int
+ {
+ if ($this->startDate !== null) {
+ return $this->startDate->getTimestamp();
+ }
+
+ return $this->getTimeStampSinceDays($this->queriesDays);
+ }
+
+ /**
+ * End date can not be set by default in typoscript constants and is always now, so one override getter is enough
+ */
+ public function getEndDateTimestamp(): int
+ {
+ if ($this->endDate !== null) {
+ return $this->endDate->getTimestamp();
+ }
+
+ return $this->getTimeStampSinceDays(0);
+ }
+
+ protected function getTimeStampSinceDays(int $days): int
+ {
+ $now = time();
+ return $now - 86400 * $days; // 86400 seconds/day
+ }
+}
diff --git a/Classes/Domain/Search/Statistics/StatisticsRepository.php b/Classes/Domain/Search/Statistics/StatisticsRepository.php
index c3bf0ec822..6ec7148484 100644
--- a/Classes/Domain/Search/Statistics/StatisticsRepository.php
+++ b/Classes/Domain/Search/Statistics/StatisticsRepository.php
@@ -44,12 +44,16 @@ class StatisticsRepository extends AbstractRepository
* @throws DBALDriverException
* @throws DBALException|\Doctrine\DBAL\DBALException
*/
- public function getSearchStatistics(int $rootPageId, int $days = 30, int $limit = 10)
+ public function getSearchStatistics(StatisticsFilterDto $statisticsFilterDto)
{
- $now = time();
- $timeStart = (int)($now - 86400 * $days); // 86400 seconds/day
- return $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords($rootPageId, $timeStart, $limit)
- ->execute()->fetchAllAssociative();
+ return $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(
+ $statisticsFilterDto->getSiteRootPageId(),
+ $statisticsFilterDto->getQueriesStartDate(),
+ $statisticsFilterDto->getEndDateTimestamp(),
+ $statisticsFilterDto->getQueriesLimit()
+ )
+ ->execute()
+ ->fetchAllAssociative();
}
/**
@@ -63,8 +67,12 @@ public function getSearchStatistics(int $rootPageId, int $days = 30, int $limit
* @throws DBALDriverException
* @throws DBALException|\Doctrine\DBAL\DBALException
*/
- protected function getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(int $rootPageId, int $timeStart, int $limit): QueryBuilder
- {
+ protected function getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(
+ int $rootPageId,
+ int $timeStart,
+ int $timeEnd,
+ int $limit
+ ): QueryBuilder {
$countRows = $this->countByRootPageId($rootPageId);
$queryBuilder = $this->getQueryBuilder();
return $queryBuilder
@@ -75,6 +83,7 @@ protected function getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(int
->from($this->table)
->andWhere(
$queryBuilder->expr()->gt('tstamp', $timeStart),
+ $queryBuilder->expr()->lt('tstamp', $timeEnd),
$queryBuilder->expr()->eq('root_pid', $rootPageId)
)
->groupBy('keywords')
@@ -94,9 +103,14 @@ protected function getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(int
* @throws DBALDriverException
* @throws DBALException|\Doctrine\DBAL\DBALException
*/
- public function getTopKeyWordsWithHits(int $rootPageId, int $days = 30, int $limit = 10): array
+ public function getTopKeyWordsWithHits(StatisticsFilterDto $filterDto): array
{
- return $this->getTopKeyWordsWithOrWithoutHits($rootPageId, $days, $limit);
+ return $this->getTopKeyWordsWithOrWithoutHits(
+ $filterDto->getSiteRootPageId(),
+ $filterDto->getTopHitsStartDate(),
+ $filterDto->getEndDateTimestamp(),
+ $filterDto->getTopHitsLimit()
+ );
}
/**
@@ -109,9 +123,15 @@ public function getTopKeyWordsWithHits(int $rootPageId, int $days = 30, int $lim
* @throws DBALDriverException
* @throws DBALException|\Doctrine\DBAL\DBALException
*/
- public function getTopKeyWordsWithoutHits(int $rootPageId, int $days = 30, int $limit = 10): array
+ public function getTopKeyWordsWithoutHits(StatisticsFilterDto $filterDto): array
{
- return $this->getTopKeyWordsWithOrWithoutHits($rootPageId, $days, $limit, true);
+ return $this->getTopKeyWordsWithOrWithoutHits(
+ $filterDto->getSiteRootPageId(),
+ $filterDto->getNoHitsStartDate(),
+ $filterDto->getEndDateTimestamp(),
+ $filterDto->getNoHitsLimit(),
+ true
+ );
}
/**
@@ -125,12 +145,20 @@ public function getTopKeyWordsWithoutHits(int $rootPageId, int $days = 30, int $
* @throws DBALException|\Doctrine\DBAL\DBALException
* @throws DBALDriverException
*/
- protected function getTopKeyWordsWithOrWithoutHits(int $rootPageId, int $days = 30, int $limit = 10, bool $withoutHits = false): array
- {
- $now = time();
- $timeStart = $now - 86400 * $days; // 86400 seconds/day
+ protected function getTopKeyWordsWithOrWithoutHits(
+ int $rootPageId,
+ int $timeStart,
+ int $timeEnd,
+ int $limit = 10,
+ bool $withoutHits = false
+ ): array {
+ $queryBuilder = $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords(
+ $rootPageId,
+ $timeStart,
+ $timeEnd,
+ $limit
+ );
- $queryBuilder = $this->getPreparedQueryBuilderForSearchStatisticsAndTopKeywords($rootPageId, $timeStart, $limit);
// Check if we want without or with hits
if ($withoutHits === true) {
$queryBuilder->andWhere($queryBuilder->expr()->eq('num_found', 0));
@@ -151,12 +179,10 @@ protected function getTopKeyWordsWithOrWithoutHits(int $rootPageId, int $days =
* @throws DBALException|\Doctrine\DBAL\DBALException
* @throws DBALDriverException
*/
- public function getQueriesOverTime(int $rootPageId, int $days = 30, int $bucketSeconds = 3600): array
+ public function getQueriesOverTime(StatisticsFilterDto $statisticsFilterDto, int $bucketSeconds = 3600): array
{
- $now = time();
- $timeStart = $now - 86400 * $days; // 86400 seconds/day
-
$queryBuilder = $this->getQueryBuilder();
+
return $queryBuilder
->addSelectLiteral(
'FLOOR(tstamp/' . $bucketSeconds . ') AS bucket',
@@ -165,8 +191,9 @@ public function getQueriesOverTime(int $rootPageId, int $days = 30, int $bucketS
)
->from($this->table)
->andWhere(
- $queryBuilder->expr()->gt('tstamp', $timeStart),
- $queryBuilder->expr()->eq('root_pid', $rootPageId)
+ $queryBuilder->expr()->gt('tstamp', $statisticsFilterDto->getQueriesStartDate()),
+ $queryBuilder->expr()->lt('tstamp', $statisticsFilterDto->getEndDateTimestamp()),
+ $queryBuilder->expr()->eq('root_pid', $statisticsFilterDto->getSiteRootPageId())
)
->groupBy('bucket', 'timestamp')
->orderBy('bucket', 'ASC')
diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf
index f32895a622..304d619d48 100644
--- a/Resources/Private/Language/locallang.xlf
+++ b/Resources/Private/Language/locallang.xlf
@@ -373,6 +373,18 @@
+
+
+
+
+
+
+
+
+
+
+
+