Skip to content

Commit

Permalink
Refactor ChartByMonth class to add caching and dynamic month range
Browse files Browse the repository at this point in the history
  • Loading branch information
ewilan-riviere committed Jan 2, 2024
1 parent 1888b88 commit a166db9
Showing 1 changed file with 96 additions and 12 deletions.
108 changes: 96 additions & 12 deletions src/Filament/Config/FilamentChart/ChartByMonth.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
namespace Kiwilan\Steward\Filament\Config\FilamentChart;

use Carbon\CarbonPeriod;
use Closure;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

/**
Expand All @@ -17,10 +20,15 @@ class ChartByMonth
protected function __construct(
protected string $table,
protected string $field = 'created_at',
protected bool $autoYear = false,
protected ?int $year = null,
protected string $label = '',
protected array $where = [],
protected ?string $id = null,
protected bool $withCache = false,
protected ?Collection $data = null,
protected ?int $startMonth = null,
protected ?int $endMonth = null,
) {
}

Expand Down Expand Up @@ -64,6 +72,16 @@ public function field(string $field): self
return $this;
}

/**
* Set the cache for the chart.
*/
public function withCache(): self
{
$this->withCache = true;

return $this;
}

/**
* Set the where clause for the query.
*
Expand All @@ -81,10 +99,23 @@ public function where(array $where): self
*/
public function get()
{
if (! $this->year) {
$this->id = uniqid();
$this->id = "statsByMonth_{$this->id}";

if (! $this->year || $this->year === now()->year) {
$this->autoYear = true;
$this->year = now()->year;
}

if ($this->autoYear) {
$currentMonth = now()->month;
$this->startMonth = $currentMonth - 11;
$this->endMonth = $currentMonth;
} else {
$this->startMonth = 1;
$this->endMonth = 12;
}

$this->data = $this->setData();

return [
Expand All @@ -95,7 +126,7 @@ public function get()
'fill' => 'start',
],
],
'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
'labels' => $this->generateMonthLabels(),
];
}

Expand All @@ -104,6 +135,14 @@ public function get()
*/
private function setData(): Collection
{
if ($this->withCache) {
$cache = Cache::get($this->id);

if ($cache) {
return $cache;
}
}

$query = DB::table($this->table)
->selectRaw('
count(id) as total,
Expand All @@ -120,23 +159,68 @@ private function setData(): Collection
}
}

$query = $query->whereYear($this->field, '=', $this->year);
// Get data only for the last 11 months and the current month
$query = $query->where(function ($query) {
$query->whereYear($this->field, '=', $this->autoYear ? $this->year - 1 : $this->year)
->orWhere(function ($query) {
$query->whereYear($this->field, '=', $this->year)
->whereMonth($this->field, '>=', $this->startMonth)
->whereMonth($this->field, '<=', $this->endMonth)
;
})
;
});

$group = $query->groupBy('period');
$data = $group->get()->keyBy('period');

$periods = collect([]);
$this->carbonPeriod(fn ($period) => $periods->push($period->format('M Y')));
$map = $periods->map(fn ($period) => $data->get($period)->total ?? 0);

if ($this->withCache) {
Cache::remember(
$this->id,
// Clears cache at the start of next month
now()->addMonth()->startOfMonth()->startOfDay(),
fn () => $map,
);
}

foreach (CarbonPeriod::create("{$this->year}-01-01", '1 month', "{$this->year}-12-01") as $period) {
$periods->push($period->format('M Y'));
return $map;
}

/**
* Get the chart data.
*
* @param Closure(\Carbon\CarbonInterface|null $period): void $closure
*/
private function carbonPeriod(Closure $closure): void
{
if ($this->autoYear) {
$paramStart = now()->subMonths(12)->startOfMonth();
$paramEnd = now()->startOfMonth();
} else {
$paramStart = "{$this->year}-01-01";
$paramEnd = "{$this->year}-12-01";
}

// $stats = Cache::remember(
// 'statsByMonth',
// // Clears cache at the start of next month
// now()->addMonth()->startOfMonth()->startOfDay(),
// fn () => $this->getStatsByMonth()
// );
foreach (CarbonPeriod::create($paramStart, '1 month', $paramEnd) as $period) {
$closure($period);
}
}

/**
* Generate month labels based on the specified range.
*
* @return string[]
*/
private function generateMonthLabels(): array
{
$months = collect([]);

$this->carbonPeriod(fn ($period) => $months->push($period->format('M Y')));

return $periods->map(fn ($period) => $data->get($period)->total ?? 0);
return $months->toArray();
}
}

0 comments on commit a166db9

Please sign in to comment.