Files
ladill-link/app/Services/Link/LinkClickRecorder.php
T
isaaccladandCursor 0e5e0f6ca5
Deploy Ladill Link / deploy (push) Successful in 32s
Add device, platform, and country analytics to link show page.
Record parsed user-agent and geo data on clicks, then surface breakdowns and richer recent-click context on per-link and account analytics views.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-27 19:32:40 +00:00

62 lines
2.0 KiB
PHP

<?php
namespace App\Services\Link;
use App\Models\LinkClick;
use App\Models\LinkWallet;
use App\Models\ShortLink;
use App\Support\Link\LinkGeoResolver;
use App\Support\Link\LinkUserAgentParser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class LinkClickRecorder
{
public function record(ShortLink $link, Request $request): void
{
$ipHash = hash('sha256', $request->ip().'|'.config('app.key'));
$windowHours = (int) config('link.click_unique_window_hours', 24);
$isUnique = ! LinkClick::query()
->where('short_link_id', $link->id)
->where('ip_hash', $ipHash)
->where('clicked_at', '>=', now()->subHours($windowHours))
->exists();
$parsed = LinkUserAgentParser::parse((string) $request->userAgent());
DB::transaction(function () use ($link, $request, $ipHash, $isUnique, $parsed) {
LinkClick::create([
'short_link_id' => $link->id,
'ip_hash' => $ipHash,
'user_agent' => $this->truncate($request->userAgent(), 512),
'referer' => $this->truncate($request->header('referer'), 512),
'device_type' => $parsed['device_type'],
'browser' => $parsed['browser'],
'os' => $parsed['os'],
'country' => LinkGeoResolver::countryCode($request),
'is_unique' => $isUnique,
'clicked_at' => now(),
]);
$link->increment('clicks_total');
if ($isUnique) {
$link->increment('unique_clicks_total');
}
$link->update(['last_clicked_at' => now()]);
LinkWallet::query()
->where('user_id', $link->user_id)
->increment('clicks_total');
});
}
private function truncate(?string $value, int $max): ?string
{
if ($value === null) {
return null;
}
return mb_strlen($value) > $max ? mb_substr($value, 0, $max) : $value;
}
}