Completed
Push — master ( 0941d8...028b7a )
by Matt
16s queued 13s
created

StatsController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\Component\Routing\Generator\UrlGeneratorInterface;
11
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
12
use Symfony\UX\Chartjs\Model\Chart;
13
14
class StatsController extends AbstractController
15
{
16
    const WANDER_NUMBER_COLOUR = '#2491B3';
17
    const WANDER_DISTANCE_COLOUR = '#ffb266';
18
    const IMAGES_NUMBER_COLOUR = '#ae411e';
19
    const IMAGES_COLOUR_STACK = [
20
        // Generated from a couple of our base colours using
21
        // Aquarelo https://setapp.com/apps/aquarelo
22
        '#000000', // 0 star  -- shouldn't really be any of these, as that means "unrated"
23
        '#940606', // 1 star sangria: ;
24
        '#ae411e', // 2 star dark-venetian-red: ;
25
        '#c97d36', // 3 star light-bronze: ;
26
        '#e4b84e', // 4 star anzac: ;
27
        '#fff466', // 5 star $yellowish: ;
28
    ];
29
30
    /** @var UrlGeneratorInterface */
31
    private $router;
32
33
    public function __construct(UrlGeneratorInterface $router)
34
    {
35
        $this->router = $router;
36
    }
37
38
    /**
39
     * @Route("/stats", name="stats_index")
40
     */
41
    public function index(
42
        StatsService $statsService,
43
        ChartBuilderInterface $chartBuilder
44
    ): Response {
45
        $wanderStats = $statsService->getWanderStats();
46
        $imageStats = $statsService->getImageStats();
47
        $imageLocationStats = $statsService->getImageLocationStats();
48
49
        $wanderDataSeries =
50
            [
51
                [
52
                    'label' => 'Number of Wanders',
53
                    'colour' => self::WANDER_NUMBER_COLOUR,
54
                    'extractFunction' => fn($dp): int => $dp['numberOfWanders'],
55
                ],
56
                [
57
                    'label' => 'Distance Walked (km)',
58
                    'colour' => self::WANDER_DISTANCE_COLOUR,
59
                    'extractFunction' => fn($dp): string => number_format($dp['totalDistance'] / 1000.0, 2)
60
                ]
61
            ];
62
63
        $monthlyWanderChart = $chartBuilder
64
            ->createChart(Chart::TYPE_BAR)
65
            ->setData($this->generatePeriodicChartData($wanderStats['monthlyStats'], $wanderDataSeries));
66
67
        $yearlyWanderChart = $chartBuilder
68
            ->createChart(Chart::TYPE_BAR)
69
            ->setData($this->generatePeriodicChartData($wanderStats['yearlyStats'], $wanderDataSeries));
70
71
        $imageDataSeries = [];
72
        for ($rating = 0; $rating <= 5; $rating++) {
73
            $imageDataSeries[] = [
74
                'label' => "Photos (Rated: $rating stars)",
75
                'colour' => self::IMAGES_COLOUR_STACK[$rating],
76
                'extractFunction' => fn($dp): int => $dp['numberOfImagesByRating'][$rating],
77
                'rating' => $rating
78
            ];
79
        }
80
81
        $monthlyImagesChart = $chartBuilder
82
            ->createChart(Chart::TYPE_BAR)
83
            ->setData($this->generatePeriodicChartData($wanderStats['monthlyStats'], $imageDataSeries))
84
            ->setOptions([
85
                'scales' => [
86
                    'x' => [
87
                        'stacked' => true
88
                    ],
89
                    'y' => [
90
                        'stacked' => true
91
                    ]
92
                ]
93
            ]);
94
95
        $yearlyImagesChart = $chartBuilder
96
            ->createChart(Chart::TYPE_BAR)
97
            ->setData($this->generatePeriodicChartData($wanderStats['yearlyStats'], $imageDataSeries))
98
            ->setOptions([
99
                'scales' => [
100
                    'x' => [
101
                        'stacked' => true
102
                    ],
103
                    'y' => [
104
                        'stacked' => true
105
                    ]
106
                ]
107
            ]);
108
109
        $locationsChart = $chartBuilder
110
            ->createChart(Chart::TYPE_BAR)
111
            ->setOptions([
112
                'maintainAspectRatio' => false,
113
                'indexAxis' => 'y',
114
                'plugins' => [
115
                    'legend' => [
116
                        'display' => false
117
                    ]
118
                ]
119
            ])
120
            ->setData([
121
                'labels' => array_keys($imageLocationStats),
122
                'urls' => array_map(fn($l): string => $this->router->generate('image_index', ['location' => $l]), array_keys($imageLocationStats)),
123
                'datasets' => [
124
                    [
125
                        'label' => 'Number of Photos',
126
                        'backgroundColor' => RandomColor::many(count($imageLocationStats)),
127
                        'borderColor' => 'black',
128
                        'borderWidth' => 1,
129
                        'borderRadius' => 5,
130
                        'data' => array_values($imageLocationStats),
131
                    ]
132
                ]
133
            ]);
134
135
        return $this->render('stats/index.html.twig', [
136
            'imageStats' => $imageStats,
137
            'wanderStats' => $wanderStats,
138
            'imageLocationStats' => $imageLocationStats,
139
            'monthlyWanderChart' => $monthlyWanderChart,
140
            'yearlyWanderChart' => $yearlyWanderChart,
141
            'monthlyImagesChart' => $monthlyImagesChart,
142
            'yearlyImagesChart' => $yearlyImagesChart,
143
            'locationsChart' => $locationsChart
144
        ]);
145
    }
146
147
    /**
148
     * @param array<string, mixed> $sourceStats
149
     * @param array<int, array<string, mixed>> $seriesDefinitions
150
     * @return array<string, mixed>
151
     */
152
    private function generatePeriodicChartData(
153
        array $sourceStats,
154
        array $seriesDefinitions
155
    ): array {
156
        $data = [
157
            'labels' => array_map(fn($dp): string => $dp['periodLabel'], $sourceStats),
158
        ];
159
        foreach ($seriesDefinitions as $series) {
160
            $data['datasets'][] = [
161
                'label' => $series['label'],
162
                'backgroundColor' => $series['colour'],
163
                'borderColor' => 'black',
164
                'borderWidth' => 1,
165
                'borderRadius' => 5,
166
                'data' => array_map($series['extractFunction'], $sourceStats),
167
            ];
168
            if (array_key_exists('rating', $series)) {
169
                $data['urls'][] = array_map(function ($dp) use ($series): string {
170
                    $params = [
171
                        'rating' => $series['rating'],
172
                        'year' => $dp['year']
173
                    ];
174
                    if ($dp['periodType'] === 'month') {
175
                        $params['month'] = $dp['month'];
176
                    }
177
                    return $this->router->generate('image_index', $params);
178
                }, $sourceStats);
179
            }
180
        }
181
        return $data;
182
    }
183
}
184