diff --git a/src/Controller/Administration/VisitorAnalyticsController.php b/src/Controller/Administration/VisitorAnalyticsController.php index 29f263d..cb2533c 100644 --- a/src/Controller/Administration/VisitorAnalyticsController.php +++ b/src/Controller/Administration/VisitorAnalyticsController.php @@ -20,6 +20,9 @@ class VisitorAnalyticsController extends AbstractController $visitsLast24Hours = $visitRepository->countVisitsSince(new \DateTimeImmutable('-24 hours')); $visitsLast7Days = $visitRepository->countVisitsSince(new \DateTimeImmutable('-7 days')); + // Most read articles in the last 24 hrs + $topArticlesLast24Hours = $visitRepository->getMostVisitedArticlesSince(new \DateTimeImmutable('-24 hours'), 5); + // Visits by route for the last 7 days $routeVisitCountsLast7Days = $visitRepository->getVisitCountByRoute(new \DateTimeImmutable('-7 days')); @@ -75,6 +78,7 @@ class VisitorAnalyticsController extends AbstractController 'topRoutesAllTime' => $topRoutesAllTime, 'recentVisitRecords' => $recentVisitRecords, 'dailyUniqueVisitorCountsLast7Days' => $dailyUniqueVisitorCountsLast7Days, + 'topArticlesLast24Hours' => $topArticlesLast24Hours, ]); } } diff --git a/src/Repository/VisitRepository.php b/src/Repository/VisitRepository.php index a04da67..21c8201 100644 --- a/src/Repository/VisitRepository.php +++ b/src/Repository/VisitRepository.php @@ -204,4 +204,23 @@ class VisitRepository extends ServiceEntityRepository } return round(($singleVisitSessions / $totalSessions) * 100, 2); } + + /** + * Returns the top N most visited articles since a given datetime. + * Only considers routes matching /article/d/{slug}. + * Returns array: [ 'route' => string, 'count' => int ] + */ + public function getMostVisitedArticlesSince(\DateTimeImmutable $since, int $limit = 5): array + { + $qb = $this->createQueryBuilder('v') + ->select('v.route, COUNT(v.id) as count') + ->where('v.visitedAt >= :since') + ->andWhere('v.route LIKE :articlePath') + ->setParameter('since', $since, \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE) + ->setParameter('articlePath', '/article/d/%') + ->groupBy('v.route') + ->orderBy('count', 'DESC') + ->setMaxResults($limit); + return $qb->getQuery()->getResult(); + } } diff --git a/templates/admin/analytics.html.twig b/templates/admin/analytics.html.twig index d8e16f5..723acd1 100644 --- a/templates/admin/analytics.html.twig +++ b/templates/admin/analytics.html.twig @@ -64,6 +64,30 @@ +
+

Top 5 Visited Articles (Last 24 Hours)

+ {% if topArticlesLast24Hours|length > 0 %} + + + + + + + + + {% for stat in topArticlesLast24Hours %} + + + + + {% endfor %} + +
Article PathVisits
{{ stat.route }}{{ stat.count }}
+ {% else %} +

No article visits recorded in the last 24 hours.

+ {% endif %} +
+

Visits Per Day (Last 30 Days)

{% if dailyVisitCountsLast30Days|length > 0 %}