Passed
Push — master ( 7f6cca...cd9a62 )
by Matt
04:08
created

StatsService::getWanderStats()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 56
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 33
nc 1
nop 0
dl 0
loc 56
rs 9.392
c 2
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
64
            // General statistics
65
            $wanderStats = $this->wanderRepository
66
                ->createQueryBuilder('w')
67
                ->select('COUNT(w.id) as totalCount')
68
                ->addSelect('COUNT(w.title) as countWithTitle')
69
                ->addSelect('COUNT(w.description) as countWithDescription')
70
                ->addSelect('COALESCE(SUM(w.distance), 0) as totalDistance')
71
                ->addSelect('COALESCE(SUM(w.cumulativeElevationGain), 0) as totalCumulativeElevationGain')
72
                ->getQuery()
73
                ->getOneOrNullResult();
74
75
            $wanderStats['hasWanders'] = $wanderStats['totalCount'] > 0;
76
77
            // Durations
78
            // Doctrine doesn't support calculating a difference
79
            // in seconds from two datetime values via ORM. Let's
80
            // go raw.
81
            $conn = $this->entityManager->getConnection();
82
            $sql = 'SELECT
83
                        COALESCE(SUM(TIME_TO_SEC(TIMEDIFF(end_time, start_time))), 0) AS totalDuration,
84
                        COALESCE(AVG(TIME_TO_SEC(TIMEDIFF(end_time, start_time))), 0) AS averageDuration
85
                    FROM wander
86
                ';
87
            $stmt = $conn->prepare($sql);
88
            $stmt->execute();
89
            $result = $stmt->fetchAssociative();
90
91
            $wanderStats['totalDuration'] = CarbonInterval::seconds($result['totalDuration'])->cascade();
92
            $wanderStats['averageDuration'] = CarbonInterval::seconds($result['averageDuration'])->cascade();
93
94
            $wanderStats['totalDurationForHumans'] = $wanderStats['totalDuration']->forHumans(['short' => true]);
95
            $wanderStats['averageDurationForHumans'] = $wanderStats['averageDuration']->forHumans(['short' => true]);
96
97
            // Distances
98
            $wanderStats['shortestWanderDistance'] = $this->wanderRepository->findShortest();
99
            $wanderStats['longestWanderDistance'] = $this->wanderRepository->findLongest();
100
            $wanderStats['averageWanderDistance'] = $this->wanderRepository->findAverageDistance();
101
102
            // Specialist stuff
103
            $qb = $this->wanderRepository
104
                ->createQueryBuilder('w');
105
            $wanderStats['imageProcessingBacklog'] = $this->wanderRepository
106
                ->addWhereHasImages($qb, false)
107
                ->select('COUNT(w.id)')
108
                ->getQuery()
109
                ->getSingleScalarResult();
110
111
            return $wanderStats;
112
        });
113
114
        return $stats;
115
    }
116
}
117