Passed
Push — master ( 1f6ef1...8269e9 )
by Matt
05:09
created

StatsService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 10
rs 10
1
<?php
2
3
namespace App\Service;
4
5
use App\Entity\Wander;
6
use App\Repository\ImageRepository;
7
use App\Repository\WanderRepository;
8
use Carbon\CarbonInterval;
9
use Doctrine\ORM\EntityManager;
10
use Doctrine\ORM\EntityManagerInterface;
11
use Doctrine\ORM\EntityRepository;
12
use Symfony\Contracts\Cache\CacheInterface;
13
use Symfony\Contracts\Cache\ItemInterface;
14
use Symfony\Contracts\Cache\TagAwareCacheInterface;
15
16
class StatsService
17
{
18
    /** @var ImageRepository */
19
    private $imageRepository;
20
21
    /** @var WanderRepository */
22
    private $wanderRepository;
23
24
    /** @var TagAwareCacheInterface */
25
    private $cache;
26
27
    /** @var EntityManagerInterface */
28
    private $entityManager;
29
30
    public function __construct(
31
        ImageRepository $imageRepository,
32
        WanderRepository $wanderRepository,
33
        TagAwareCacheInterface $cache,
34
        EntityManagerInterface $entityManager)
35
    {
36
        $this->imageRepository = $imageRepository;
37
        $this->wanderRepository = $wanderRepository;
38
        $this->cache = $cache;
39
        $this->entityManager = $entityManager;
40
    }
41
42
    public function getImageStats(): array
43
    {
44
        $stats = $this->cache->get('image_stats', function(ItemInterface $item) {
45
            $item->tag('stats');
46
            $imageStats = $this->imageRepository
47
                ->createQueryBuilder('i')
48
                ->select('COUNT(i.id) as totalCount')
49
                ->addSelect('COUNT(i.latlng) as countWithCoords')
50
                ->addSelect('COUNT(i.title) as countWithTitle')
51
                ->addSelect('COUNT(i.description) as countWithDescription')
52
                ->getQuery()
53
                ->getOneOrNullResult();
54
            return $imageStats;
55
        });
56
        return $stats;
57
    }
58
59
    public function getWanderStats(): array
60
    {
61
        $stats = $this->cache->get('wander_stats', function(ItemInterface $item) {
62
            $item->tag('stats');
63
            $wanderStats = $this->wanderRepository
64
                ->createQueryBuilder('w')
65
                ->select('COUNT(w.id) as totalCount')
66
                ->addSelect('COUNT(w.title) as countWithTitle')
67
                ->addSelect('COUNT(w.description) as countWithDescription')
68
                //->addSelect('SUM(w.durationSeconds) as totalDuration')
69
                ->addSelect('COALESCE(SUM(w.distance), 0) as totalDistance')
70
                ->addSelect('COALESCE(SUM(w.cumulativeElevationGain), 0) as totalCumulativeElevationGain')
71
                ->getQuery()
72
                ->getOneOrNullResult();
73
74
            $wanderStats['hasWanders'] = $wanderStats['totalCount'] > 0;
75
76
            // Doctrine doesn't support calculating a difference
77
            // in seconds from two datetime values via ORM. Let's
78
            // go raw.
79
            $conn = $this->entityManager->getConnection();
80
            $sql = 'SELECT COALESCE(SUM(TIME_TO_SEC(TIMEDIFF(end_time, start_time))), 0) FROM wander';
81
            $stmt = $conn->prepare($sql);
82
            $stmt->execute();
83
            $seconds = $stmt->fetchOne();
84
85
            $interval = CarbonInterval::seconds($seconds)->cascade();
86
87
            $wanderStats['totalDuration'] = $interval;
88
            $wanderStats['totalDurationForHumans'] = $interval->forHumans([
89
                    'short' => true
90
                ]);
91
92
            // Set up defaults for average, in case we have no wanders
93
            $wanderStats['averageWanderDuration'] = 0;
94
            $wanderStats['averageWanderDurationForHumans'] = '0s';
95
96
            if ($wanderStats['hasWanders']) { // Avoid divide by zero
97
                $interval = CarbonInterval::seconds($seconds / $wanderStats['totalCount'])->cascade();
98
                $wanderStats['averageDuration'] = $interval;
99
                $wanderStats['averageDurationForHumans'] = $interval->forHumans([
100
                        'short' => true
101
                    ]);
102
            }
103
104
            $wanderStats['longestWanderDistance'] = $this->wanderRepository
105
                ->createQueryBuilder('w')
106
                ->select('w.id, w.distance')
107
                ->orderBy('w.distance', 'desc')
108
                ->setMaxResults(1)
109
                ->getQuery()
110
                ->getOneOrNullResult();
111
112
            $wanderStats['shortestWanderDistance'] = $this->wanderRepository
113
                ->createQueryBuilder('w')
114
                ->select('w.id, w.distance')
115
                ->orderBy('w.distance', 'asc')
116
                ->setMaxResults(1)
117
                ->getQuery()
118
                ->getOneOrNullResult();
119
120
            $wanderStats['averageWanderDistance'] = $this->wanderRepository
121
                ->createQueryBuilder('w')
122
                ->select('AVG(w.distance)')
123
                ->getQuery()
124
                ->getSingleScalarResult() ?? 0;
125
126
            $qb = $this->wanderRepository
127
                ->createQueryBuilder('w');
128
            $wanderStats['imageProcessingBacklog'] = $this->wanderRepository->addWhereHasImages($qb, false)
129
                ->select('COUNT(w.id)')
130
                ->getQuery()
131
                ->getSingleScalarResult();
132
133
            return $wanderStats;
134
        });
135
136
        return $stats;
137
    }
138
}