Completed
Push — master ( 846a7c...cf7dbf )
by Matt
19s queued 12s
created

StatsController   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 84
c 5
b 0
f 0
dl 0
loc 140
rs 10
wmc 4

2 Methods

Rating   Name   Duplication   Size   Complexity  
B index() 0 102 2
A generatePeriodicChartData() 0 18 2
1
<?php
2
3
namespace App\Controller;
4
5
use App\Service\StatsService;
6
use Colors\RandomColor;
7
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
8
use Symfony\Component\HttpFoundation\Response;
9
use Symfony\Component\Routing\Annotation\Route;
10
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
11
use Symfony\UX\Chartjs\Model\Chart;
12
13
class StatsController extends AbstractController
14
{
15
    const WANDER_NUMBER_COLOUR = '#2491B3';
16
    const WANDER_DISTANCE_COLOUR = '#ffb266';
17
    const IMAGES_NUMBER_COLOUR = '#BF5439';
18
    const IMAGES_COLOUR_STACK = [
19
        'black', '#3F0B1B', '#7A1631', '#CF423C', '#FC7D49', '#BF5439'
20
    ];
21
22
    /**
23
     * @Route("/stats", name="stats_index")
24
     */
25
    public function index(
26
        StatsService $statsService,
27
        ChartBuilderInterface $chartBuilder
28
    ): Response {
29
        $wanderStats = $statsService->getWanderStats();
30
        $imageStats = $statsService->getImageStats();
31
        $imageLocationStats = $statsService->getImageLocationStats();
32
33
        $wanderDataSeries =
34
            [
35
                [
36
                    'label' => 'Number of Wanders',
37
                    'colour' => self::WANDER_NUMBER_COLOUR,
38
                    'extractFunction' => fn($dp): int => $dp['numberOfWanders'],
39
                ],
40
                [
41
                    'label' => 'Distance Walked (km)',
42
                    'colour' => self::WANDER_DISTANCE_COLOUR,
43
                    'extractFunction' => fn($dp): string => number_format($dp['totalDistance'] / 1000.0, 2)
44
                ]
45
            ];
46
47
        $monthlyWanderChart = $chartBuilder
48
            ->createChart(Chart::TYPE_BAR)
49
            ->setData($this->generatePeriodicChartData($wanderStats['monthlyStats'], $wanderDataSeries));
50
51
        $yearlyWanderChart = $chartBuilder
52
            ->createChart(Chart::TYPE_BAR)
53
            ->setData($this->generatePeriodicChartData($wanderStats['yearlyStats'], $wanderDataSeries));
54
55
        $imageDataSeries = [];
56
        for ($rating = 0; $rating <= 5; $rating++) {
57
            $imageDataSeries[] = [
58
                'label' => "Photos (Rated: $rating stars)",
59
                'colour' => self::IMAGES_COLOUR_STACK[$rating],
60
                'extractFunction' => fn($dp): int => $dp['numberOfImagesByRating'][$rating],
61
            ];
62
        }
63
64
        $monthlyImagesChart = $chartBuilder
65
            ->createChart(Chart::TYPE_BAR)
66
            ->setData($this->generatePeriodicChartData($wanderStats['monthlyStats'], $imageDataSeries))
67
            ->setOptions([
68
                'scales' => [
69
                    'x' => [
70
                        'stacked' => true
71
                    ],
72
                    'y' => [
73
                        'stacked' => true
74
                    ]
75
                ]
76
            ]);
77
78
        $yearlyImagesChart = $chartBuilder
79
            ->createChart(Chart::TYPE_BAR)
80
            ->setData($this->generatePeriodicChartData($wanderStats['yearlyStats'], $imageDataSeries))
81
            ->setOptions([
82
                'scales' => [
83
                    'x' => [
84
                        'stacked' => true
85
                    ],
86
                    'y' => [
87
                        'stacked' => true
88
                    ]
89
                ]
90
            ]);
91
92
        $locationsChart = $chartBuilder
93
            ->createChart(Chart::TYPE_BAR)
94
            ->setOptions([
95
                'maintainAspectRatio' => false,
96
                'indexAxis' => 'y',
97
                'plugins' => [
98
                    'legend' => [
99
                        'display' => false
100
                    ]
101
                ]
102
            ])
103
            ->setData([
104
                'labels' => array_keys($imageLocationStats),
105
                'datasets' => [
106
                    [
107
                        'label' => 'Number of Photos',
108
                        'backgroundColor' => RandomColor::many(count($imageLocationStats)),
109
                        'borderColor' => 'black',
110
                        'borderWidth' => 1,
111
                        'borderRadius' => 5,
112
                        'data' => array_values($imageLocationStats)
113
                    ]
114
                ]
115
            ]);
116
117
        return $this->render('stats/index.html.twig', [
118
            'controller_name' => 'StatsController', // TODO: Remove this boilerplate
119
            'imageStats' => $imageStats,
120
            'wanderStats' => $wanderStats,
121
            'imageLocationStats' => $imageLocationStats,
122
            'monthlyWanderChart' => $monthlyWanderChart,
123
            'yearlyWanderChart' => $yearlyWanderChart,
124
            'monthlyImagesChart' => $monthlyImagesChart,
125
            'yearlyImagesChart' => $yearlyImagesChart,
126
            'locationsChart' => $locationsChart
127
        ]);
128
    }
129
130
    /**
131
     * @param array<string, mixed> $sourceStats
132
     * @param array<int, array<string, mixed>> $seriesDefinitions
133
     * @return array<string, mixed>
134
     */
135
    private function generatePeriodicChartData(
136
        array $sourceStats,
137
        array $seriesDefinitions
138
    ): array {
139
        $data = [
140
            'labels' => array_map(fn($dp): string => $dp['periodLabel'], $sourceStats)
141
        ];
142
        foreach ($seriesDefinitions as $series) {
143
            $data['datasets'][] = [
144
                'label' => $series['label'],
145
                'backgroundColor' => $series['colour'],
146
                'borderColor' => 'black',
147
                'borderWidth' => 1,
148
                'borderRadius' => 5,
149
                'data' => array_map($series['extractFunction'], $sourceStats)
150
            ];
151
        }
152
        return $data;
153
    }
154
}
155