File size: 2,372 Bytes
45dc401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php

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 AnalyticsVisitorRepository extends BaseRepository
{
    public function __construct(private readonly UuidGenerator $ids) {}

    protected function table(): string
    {
        return 'analytics_visitors';
    }

    protected function hasDeletedAtColumn(): bool
    {
        return false;
    }

    public function findByToken(string $token): ?\stdClass
    {
        return DB::table($this->table())->where('visitor_token', $token)->first();
    }

    public function findById(string $id): ?\stdClass
    {
        return DB::table($this->table())->where('id', $id)->first();
    }

    /**
     * Find-or-create a visitor by token, updating last_seen_at on every call.
     * Returns the visitor id.
     */
    public function upsert(string $token, ?string $memberId): string
    {
        $now = Carbon::now()->toDateTimeString();
        $existing = $this->findByToken($token);

        if ($existing) {
            $patch = ['last_seen_at' => $now, 'updated_at' => $now];
            if ($memberId !== null && $existing->member_id === null) {
                $patch['member_id'] = $memberId;
            }
            DB::table($this->table())->where('id', $existing->id)->update($patch);
            return $existing->id;
        }

        $id = $this->ids->generate();
        DB::table($this->table())->insert([
            'id'            => $id,
            'visitor_token' => $token,
            'member_id'     => $memberId,
            'first_seen_at' => $now,
            'last_seen_at'  => $now,
            'created_at'    => $now,
            'updated_at'    => $now,
        ]);
        return $id;
    }

    /**
     * Link an anonymous visitor to a known member after login.
     * Only writes when member_id is not already set to prevent duplicate stitches.
     */
    public function stitch(string $visitorId, string $memberId): void
    {
        DB::table($this->table())
            ->where('id', $visitorId)
            ->whereNull('member_id')
            ->update([
                'member_id'  => $memberId,
                'updated_at' => Carbon::now()->toDateTimeString(),
            ]);
    }
}