table = $db->prefix . 'us_availability'; } public function insert(AvailabilitySlot $slot): int { $this->db->insert( $this->table, [ 'instructor_id' => $slot->instructorId, 'start_dt' => $slot->startDt, 'end_dt' => $slot->endDt, 'is_booked' => 0, 'created_at' => current_time('mysql'), ], ['%d', '%s', '%s', '%d', '%s'] ); return $this->db->insert_id; } /** * Find unbooked slots, optionally filtered by instructor and date range. * * @return list */ public function findAvailable(int $instructorId = 0, string $from = '', string $to = ''): array { $where = ['is_booked = 0']; $params = []; if ($instructorId > 0) { $where[] = 'instructor_id = %d'; $params[] = $instructorId; } if ($from !== '') { $where[] = 'start_dt >= %s'; $params[] = $from; } if ($to !== '') { $where[] = 'end_dt <= %s'; $params[] = $to; } $whereClause = implode(' AND ', $where); $sql = "SELECT * FROM {$this->table} WHERE {$whereClause} ORDER BY start_dt ASC"; $rows = $params ? $this->db->get_results($this->db->prepare($sql, $params)) : $this->db->get_results($sql); return array_map(AvailabilitySlot::fromRow(...), $rows ?? []); } /** * Find all slots for an instructor (booked and unbooked). * * @return list */ public function findByInstructor(int $instructorId): array { $rows = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->table} WHERE instructor_id = %d ORDER BY start_dt ASC", $instructorId ) ); return array_map(AvailabilitySlot::fromRow(...), $rows ?? []); } public function findById(int $id): ?AvailabilitySlot { $row = $this->db->get_row( $this->db->prepare("SELECT * FROM {$this->table} WHERE id = %d", $id) ); return $row ? AvailabilitySlot::fromRow($row) : null; } public function markBooked(int $id): bool { return (bool) $this->db->update( $this->table, ['is_booked' => 1], ['id' => $id], ['%d'], ['%d'] ); } /** * Delete an unbooked slot. Returns false if the slot is already booked. */ public function delete(int $id): bool { return (bool) $this->db->delete( $this->table, ['id' => $id, 'is_booked' => 0], ['%d', '%d'] ); } }