pdo->prepare( 'INSERT INTO events (device_id, camera_id, event_type, severity, track_id, zone_id, occurred_at, duration_s, metrics_json, received_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' ); $st->execute([ (string)$event['device_id'], (string)$event['camera_id'], (string)$event['event_type'], (string)$event['severity'], $event['track_id'] ?? null, $event['zone_id'] ?? null, (float)$event['occurred_at'], (float)($event['duration_s'] ?? 0.0), json_encode($event['metrics'] ?? [], JSON_THROW_ON_ERROR), time(), ]); return (int)$this->pdo->lastInsertId(); } public function recent(int $limit, ?string $severity): array { if ($severity !== null) { $st = $this->pdo->prepare( 'SELECT ' . self::SELECT_COLUMNS . ' FROM events WHERE severity = ? ORDER BY occurred_at DESC, event_id DESC LIMIT ?' ); $st->bindValue(1, $severity, PDO::PARAM_STR); $st->bindValue(2, $limit, PDO::PARAM_INT); } else { $st = $this->pdo->prepare( 'SELECT ' . self::SELECT_COLUMNS . ' FROM events ORDER BY occurred_at DESC, event_id DESC LIMIT ?' ); $st->bindValue(1, $limit, PDO::PARAM_INT); } $st->execute(); return array_map(self::mapRow(...), $st->fetchAll()); } public function find(int $id): ?array { $st = $this->pdo->prepare('SELECT ' . self::SELECT_COLUMNS . ' FROM events WHERE event_id = ?'); $st->execute([$id]); $row = $st->fetch(); return $row === false ? null : self::mapRow($row); } public function acknowledge(int $id, string $user): bool { // Existence is checked separately (rather than trusting UPDATE's // rowCount()) because MySQL's PDO driver, by default, reports // "changed rows" rather than "matched rows": re-acknowledging an // already-acknowledged event by the same user would otherwise report // 0 affected rows and this method would wrongly return false. $exists = $this->pdo->prepare('SELECT 1 FROM events WHERE event_id = ? LIMIT 1'); $exists->execute([$id]); if ($exists->fetchColumn() === false) { return false; } $st = $this->pdo->prepare( 'UPDATE events SET acknowledged_by = ?, acknowledged_at = ? WHERE event_id = ?' ); $st->execute([$user, time(), $id]); return true; } private static function mapRow(array $row): array { return [ 'event_id' => (int)$row['event_id'], 'device_id' => $row['device_id'], 'camera_id' => $row['camera_id'], 'event_type' => $row['event_type'], 'severity' => $row['severity'], 'track_id' => $row['track_id'] !== null ? (int)$row['track_id'] : null, 'zone_id' => $row['zone_id'], 'occurred_at' => (float)$row['occurred_at'], 'duration_s' => (float)$row['duration_s'], 'metrics' => json_decode((string)($row['metrics_json'] ?? '[]'), true) ?? [], 'acknowledged_by' => $row['acknowledged_by'], 'acknowledged_at' => $row['acknowledged_at'] !== null ? (int)$row['acknowledged_at'] : null, ]; } }