where('token', $token)->where('is_active', 1)->first(); if (! $row) { return null; } $exp = $row['expires_at'] ?? null; if ($exp && strtotime((string) $exp) < time()) { return null; } return $row; } public function incrementViewCount(int $id): void { $this->builder()->where('id', $id)->set('view_count', 'view_count + 1', false)->update(); } /** * @return list> */ public function forResource(string $type, int $resourceId, int $workspaceId): array { return $this->where('type', $type) ->where('resource_id', $resourceId) ->where('workspace_id', $workspaceId) ->where('is_active', 1) ->orderBy('id', 'DESC') ->findAll(); } public function findOwned(int $id, int $workspaceId): ?array { $row = $this->where('id', $id)->where('workspace_id', $workspaceId)->first(); return $row ?: null; } public static function generateToken(): string { return bin2hex(random_bytes(32)); } }