php
43 lines · 8 steps
Computing rolling averages in Laravel
A service class turns daily metric rows into a per-day series with a trailing N-day rolling average.
Explained by
highlit
1<?php
2
3namespace App\Services;
4
5use App\Models\DailyMetric;
6use Carbon\CarbonPeriod;
7use Illuminate\Support\Collection;
8
9class RollingAverageCalculator
10{
11 public function __construct(private int $window = 7)
12 {
13 }
14
15 public function forRange(string $metric, \DateTimeInterface $from, \DateTimeInterface $to): Collection
16 {
17 $totals = DailyMetric::query()
18 ->where('name', $metric)
19 ->whereBetween('recorded_on', [$from, $to])
20 ->pluck('value', 'recorded_on')
21 ->mapWithKeys(fn ($value, $date) => [substr($date, 0, 10) => (float) $value]);
22
23 return collect(CarbonPeriod::create($from, $to))
24 ->map(function ($day) use ($totals) {
25 $date = $day->toDateString();
26 $windowStart = $day->copy()->subDays($this->window - 1);
27
28 $values = collect(CarbonPeriod::create($windowStart, $day))
29 ->map(fn ($d) => $totals->get($d->toDateString()))
30 ->filter(fn ($v) => $v !== null);
31
32 return [
33 'date' => $date,
34 'value' => $totals->get($date, 0.0),
35 'rolling_average' => $values->isEmpty()
36 ? null
37 : round($values->avg(), 2),
38 'samples' => $values->count(),
39 ];
40 })
41 ->values();
42 }
43}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Loading raw values into a date-keyed map once lets you compute every window with fast in-memory lookups instead of repeated queries.
- 2Iterating a CarbonPeriod gives you a gap-free day-by-day spine even when the underlying data has missing days.
- 3Tracking the sample count alongside the average makes partial or sparse windows honest rather than silently misleading.
Related explainers
php
<?php namespace App\Console\Commands;
Releasing stale document locks in Laravel
artisan-command
transactions
row-locking
Intermediate
6 steps
php
<?php namespace App\Providers;
Subdomain multi-tenancy routing in Laravel
multi-tenancy
service-container
route-binding
Advanced
7 steps
php
<?php namespace App\Broadcasting;
Authorizing presence channels in Laravel
broadcasting
authorization
presence-channels
Intermediate
3 steps
java
@RestController @RequestMapping("/api/products") public class ProductSearchController {
Binding collection query params in Spring
rest-api
query-parameters
dependency-injection
Intermediate
6 steps
php
<?php namespace App\Http\Middleware;
Resolving the current team in Laravel middleware
middleware
multi-tenancy
cookies
Intermediate
8 steps
php
<?php namespace App\Http\Controllers;
Broadcasting typing indicators in Laravel
websockets
authorization
presence-channels
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/computing-rolling-averages-in-laravel-explained-php-aac4/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.