Spaces:
Running
Running
| declare(strict_types=1); | |
| namespace App\Domain\Analytics; | |
| use App\Infrastructure\Database\BaseRepository; | |
| use App\Infrastructure\Ids\UuidGenerator; | |
| use Illuminate\Support\Carbon; | |
| use Illuminate\Support\Facades\DB; | |
| final class AnalyticsFunnelRepository extends BaseRepository | |
| { | |
| public function __construct(private readonly UuidGenerator $ids) {} | |
| protected function table(): string | |
| { | |
| return 'analytics_funnel_progress'; | |
| } | |
| protected function hasDeletedAtColumn(): bool | |
| { | |
| return false; | |
| } | |
| public function findByVisitorSessionModule(string $visitorId, string $sessionId, string $module): ?\stdClass | |
| { | |
| return DB::table($this->table()) | |
| ->where('visitor_id', $visitorId) | |
| ->where('session_id', $sessionId) | |
| ->where('module', $module) | |
| ->first(); | |
| } | |
| /** | |
| * Idempotent: returns existing id if a row already exists for this triple. | |
| */ | |
| public function start(string $visitorId, string $sessionId, string $module): string | |
| { | |
| $existing = $this->findByVisitorSessionModule($visitorId, $sessionId, $module); | |
| if ($existing) { | |
| return $existing->id; | |
| } | |
| $id = $this->ids->generate(); | |
| $now = Carbon::now()->toDateTimeString(); | |
| DB::table($this->table())->insert([ | |
| 'id' => $id, | |
| 'visitor_id' => $visitorId, | |
| 'session_id' => $sessionId, | |
| 'module' => $module, | |
| 'started_at' => $now, | |
| 'last_step_at' => $now, | |
| 'highest_step' => 0, | |
| 'submitted' => 0, | |
| 'abandoned' => 0, | |
| 'created_at' => $now, | |
| 'updated_at' => $now, | |
| ]); | |
| return $id; | |
| } | |
| /** | |
| * Advance highest_step monotonically. No-op if step is not higher than current value. | |
| */ | |
| public function advanceStep(string $id, int $step): void | |
| { | |
| $now = Carbon::now()->toDateTimeString(); | |
| DB::table($this->table()) | |
| ->where('id', $id) | |
| ->where('highest_step', '<', $step) | |
| ->update([ | |
| 'highest_step' => $step, | |
| 'last_step_at' => $now, | |
| 'updated_at' => $now, | |
| ]); | |
| } | |
| public function markSubmitted(string $id, string $applicationId, bool $feeWaived): void | |
| { | |
| $now = Carbon::now()->toDateTimeString(); | |
| DB::table($this->table())->where('id', $id)->update([ | |
| 'submitted' => 1, | |
| 'submitted_at' => $now, | |
| 'application_id' => $applicationId, | |
| 'fee_waived' => $feeWaived ? 1 : 0, | |
| 'abandoned' => 0, | |
| 'abandoned_at' => null, | |
| 'updated_at' => $now, | |
| ]); | |
| } | |
| public function markAbandoned(string $id): void | |
| { | |
| $now = Carbon::now()->toDateTimeString(); | |
| DB::table($this->table()) | |
| ->where('id', $id) | |
| ->where('submitted', 0) | |
| ->update([ | |
| 'abandoned' => 1, | |
| 'abandoned_at' => $now, | |
| 'updated_at' => $now, | |
| ]); | |
| } | |
| } | |