| Current Path : /var/www/html/redd/app/Models/Backend/ |
| Current File : /var/www/html/redd/app/Models/Backend/Visit.php |
<?php
namespace App\Models\Backend;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
#[Table('visits')]
#[Fillable([
'method', 'request', 'url', 'referer',
'languages', 'useragent', 'headers',
'device', 'platform', 'browser', 'ip',
'visitor_id', 'visitor_type', 'visitable_id', 'visitable_type', 'geo_raw',
])]
class Visit extends Model
{
protected function casts(): array
{
return [
'request' => 'array',
'languages' => 'array',
'headers' => 'array',
'geo_raw' => 'array',
];
}
// ──────────────────────────────────────
// RELATIONS
// ──────────────────────────────────────
public function visitable(): MorphTo
{
return $this->morphTo('visitable');
}
public function visitor(): MorphTo
{
return $this->morphTo('visitor');
}
// ──────────────────────────────────────
// LOGGING
// ──────────────────────────────────────
public static function log(?Request $request = null, ?Model $visitor = null, ?Model $visitable = null): ?self
{
$request ??= request();
if (!$request) {
return null;
}
$ua = $request->userAgent() ?? '';
$data = [
'method' => $request->method(),
'request' => $request->all(),
'url' => $request->fullUrl(),
'referer' => $request->header('referer'),
'languages' => $request->getLanguages() ?? [],
'useragent' => $ua,
'headers' => $request->headers->all(),
'device' => self::detectDevice($ua),
'platform' => self::detectPlatform($ua),
'browser' => self::detectBrowser($ua),
'ip' => $request->ip(),
'visitor_id' => $visitor?->id ?? Auth::id(),
'visitor_type' => $visitor?->getMorphClass() ?? (Auth::user()?->getMorphClass()),
];
if ($visitable) {
$data['visitable_id'] = $visitable->id;
$data['visitable_type'] = $visitable->getMorphClass();
}
return self::create($data);
}
// ──────────────────────────────────────
// STATS (static)
// ──────────────────────────────────────
public static function totalVisits(): int
{
return self::count();
}
public static function uniqueIps(): int
{
return self::distinct('ip')->count('ip');
}
public static function todayVisits(): int
{
return self::whereDate('created_at', today())->count();
}
public static function yesterdayVisits(): int
{
return self::whereDate('created_at', today()->subDay())->count();
}
public static function thisWeekVisits(): int
{
return self::whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()])->count();
}
public static function thisMonthVisits(): int
{
return self::whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->count();
}
public static function last3MonthsVisits(): int
{
return self::where('created_at', '>=', now()->subMonths(3))->count();
}
public static function last6MonthsVisits(): int
{
return self::where('created_at', '>=', now()->subMonths(6))->count();
}
public static function thisYearVisits(): int
{
return self::whereYear('created_at', now()->year)->count();
}
public static function lastYearVisits(): int
{
return self::where('created_at', '>=', now()->subYear())->count();
}
public static function uniqueVisitors(): int
{
return self::whereNotNull('visitor_id')
->distinct('visitor_id')
->count('visitor_id');
}
// ──────────────────────────────────────
// SCOPES
// ──────────────────────────────────────
public function scopeToday(Builder $q): Builder
{
return $q->whereDate('created_at', today());
}
public function scopeYesterday(Builder $q): Builder
{
return $q->whereDate('created_at', today()->subDay());
}
public function scopeThisWeek(Builder $q): Builder
{
return $q->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()]);
}
public function scopeThisMonth(Builder $q): Builder
{
return $q->whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year);
}
public function scopeLast3Months(Builder $q): Builder
{
return $q->where('created_at', '>=', now()->subMonths(3));
}
public function scopeLast6Months(Builder $q): Builder
{
return $q->where('created_at', '>=', now()->subMonths(6));
}
public function scopeThisYear(Builder $q): Builder
{
return $q->whereYear('created_at', now()->year);
}
public function scopeLastYear(Builder $q): Builder
{
return $q->where('created_at', '>=', now()->subYear());
}
public function scopeByVisitor(Builder $q, Model $visitor): Builder
{
return $q->where('visitor_type', $visitor->getMorphClass())
->where('visitor_id', $visitor->id);
}
public function scopeByVisitable(Builder $q, Model $visitable): Builder
{
return $q->where('visitable_type', $visitable->getMorphClass())
->where('visitable_id', $visitable->id);
}
public function scopeByDevice(Builder $q, string $device): Builder
{
return $q->where('device', $device);
}
public function scopeByBrowser(Builder $q, string $browser): Builder
{
return $q->where('browser', $browser);
}
public function scopeByPlatform(Builder $q, string $platform): Builder
{
return $q->where('platform', $platform);
}
public function scopeByIp(Builder $q, string $ip): Builder
{
return $q->where('ip', $ip);
}
public function scopeByMethod(Builder $q, string $method): Builder
{
return $q->where('method', strtoupper($method));
}
public function scopeBetween(Builder $q, $start, $end): Builder
{
return $q->whereBetween('created_at', [$start, $end]);
}
public function scopeOnline(Builder $q, int $seconds = 180): Builder
{
return $q->where('created_at', '>=', now()->subSeconds($seconds));
}
// ──────────────────────────────────────
// USER AGENT DETECTION
// ──────────────────────────────────────
private static function detectDevice(string $ua): string
{
if (preg_match('/android/i', $ua)) return 'Android';
if (preg_match('/(ipad|tablet|playbook|silk)|(android(?!.*mobile))/i', $ua)) return 'Tablet';
if (preg_match('/(mobile|iphone|ipod|blackberry|opera mini|iemobile)/i', $ua)) return 'Mobile';
return 'Desktop';
}
private static function detectPlatform(string $ua): string
{
if (preg_match('/windows nt/i', $ua)) return 'Windows';
if (preg_match('/macintosh|mac os x/i', $ua)) return 'macOS';
if (preg_match('/linux/i', $ua)) return 'Linux';
if (preg_match('/android/i', $ua)) return 'Android';
if (preg_match('/iphone|ipad|ipod/i', $ua)) return 'iOS';
return 'Unknown';
}
private static function detectBrowser(string $ua): string
{
if (preg_match('/edg/i', $ua)) return 'Edge';
if (preg_match('/chrome/i', $ua)) return 'Chrome';
if (preg_match('/safari/i', $ua)) return 'Safari';
if (preg_match('/firefox/i', $ua)) return 'Firefox';
if (preg_match('/opera|opr/i', $ua)) return 'Opera';
if (preg_match('/msie|trident/i', $ua)) return 'IE';
return 'Unknown';
}
}