*/ public static function touch(Model $record, User $user): Collection { $key = self::key($record); $cutoff = now()->subMinutes(self::TTL_MINUTES)->timestamp; $present = collect(self::entries($key)) ->filter(fn (int $seenAt) => $seenAt >= $cutoff); // Answered before this visit is recorded: nobody is ever told they // are keeping themselves company. $others = $present->keys()->reject(fn (int $id) => $id === $user->getKey()); $present[$user->getKey()] = now()->timestamp; Cache::put($key, $present->all(), now()->addMinutes(self::TTL_MINUTES)); return $others->isEmpty() ? collect() : User::query()->whereKey($others)->get(); } protected static function key(Model $record): string { return 'presence:'.$record->getMorphClass().':'.$record->getKey(); } /** * @return array */ protected static function entries(string $key): array { return (array) Cache::get($key, []); } }