pdo->prepare( 'INSERT INTO move_actions (camera_id, site, event_id, note, taken_at, created_by, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)' ); $st->execute([ (string)$action['camera_id'], $action['site'] ?? null, // denormalized from the camera's events by ActionsController // The incident that prompted this fix, when it was recorded from an event's detail // page. Nullable because an action can also be entered standalone from the report. isset($action['event_id']) ? (int)$action['event_id'] : null, (string)$action['note'], (int)$action['taken_at'], (string)$action['created_by'], time(), ]); return (int)$this->pdo->lastInsertId(); } public function recent(int $limit, ?string $site): array { $sql = 'SELECT action_id, camera_id, site, event_id, note, taken_at, created_by FROM move_actions'; $binds = []; if ($site !== null) { // Fail-closed like every other scoped list: an empty-string scope matches nothing, // and a row with no site is never visible to a scoped caller. $sql .= ' WHERE site = ?'; $binds[] = $site; } $sql .= ' ORDER BY taken_at DESC, action_id DESC LIMIT ?'; $st = $this->pdo->prepare($sql); $pos = 1; foreach ($binds as $b) $st->bindValue($pos++, $b, PDO::PARAM_STR); $st->bindValue($pos, $limit, PDO::PARAM_INT); $st->execute(); return array_map(static fn ($r) => [ 'action_id' => (int)$r['action_id'], 'camera_id' => $r['camera_id'], 'site' => $r['site'], 'event_id' => $r['event_id'] !== null ? (int)$r['event_id'] : null, 'note' => $r['note'], 'taken_at' => (int)$r['taken_at'], 'created_by' => $r['created_by'], ], $st->fetchAll()); } }