'required|integer|is_not_unique[classes.id]', 'subject_id' => 'required|integer|is_not_unique[subjects.id]', 'teacher_name' => 'required|max_length[255]', 'day_of_week' => 'required|integer|greater_than_equal_to[1]|less_than_equal_to[7]', 'start_time' => 'required|valid_date[H:i:s]', 'end_time' => 'required|valid_date[H:i:s]', 'room' => 'permit_empty|max_length[100]', ]; protected $validationMessages = []; protected $skipValidation = false; protected $cleanValidationRules = true; // Callbacks protected $allowCallbacks = true; protected $beforeInsert = []; protected $afterInsert = []; protected $beforeUpdate = []; protected $afterUpdate = []; protected $beforeFind = []; protected $afterFind = []; protected $beforeDelete = []; protected $afterDelete = []; /** * Find active schedule for class on specific day and time (uses schedule columns only). * * @deprecated Prefer getActiveScheduleRow() for slot/user as source of truth with fallback. * @param int $classId * @param int $dayOfWeek * @param string $time Time in H:i:s format * @return Schedule|null */ public function findActiveSchedule(int $classId, int $dayOfWeek, string $time): ?Schedule { return $this->where('class_id', $classId) ->where('day_of_week', $dayOfWeek) ->where('start_time <=', $time) ->where('end_time >', $time) ->first(); } /** * Get active schedule row with lesson_slots and users as source of truth. * start_time, end_time from lesson_slots; teacher_name from users; fallback to schedule columns when NULL. * * @param int $classId * @param int $dayOfWeek * @param string $time Time in H:i:s format * @return array{id: int, class_id: int, subject_id: int, teacher_user_id: int|null, teacher_name: string, room: string|null, start_time: string, end_time: string, day_of_week: int}|null */ public function getActiveScheduleRow(int $classId, int $dayOfWeek, string $time): ?array { $db = \Config\Database::connect(); $sql = 'SELECT sch.id AS id, sch.class_id, sch.subject_id, sch.teacher_user_id, ' . 'COALESCE(u.name, sch.teacher_name) AS teacher_name, sch.room, ' . 'COALESCE(ls.start_time, sch.start_time) AS start_time, COALESCE(ls.end_time, sch.end_time) AS end_time, sch.day_of_week ' . 'FROM schedules sch ' . 'LEFT JOIN lesson_slots ls ON ls.id = sch.lesson_slot_id ' . 'LEFT JOIN users u ON u.id = sch.teacher_user_id ' . 'WHERE sch.class_id = ? AND sch.day_of_week = ? ' . 'AND ( COALESCE(ls.start_time, sch.start_time) ) <= ? AND ( COALESCE(ls.end_time, sch.end_time) ) > ? ' . 'LIMIT 1'; $row = $db->query($sql, [$classId, $dayOfWeek, $time, $time])->getRowArray(); if ($row === null) { return null; } return [ 'id' => (int) $row['id'], 'class_id' => (int) $row['class_id'], 'subject_id' => (int) $row['subject_id'], 'teacher_user_id' => isset($row['teacher_user_id']) ? (int) $row['teacher_user_id'] : null, 'teacher_name' => (string) ($row['teacher_name'] ?? ''), 'room' => isset($row['room']) ? (string) $row['room'] : null, 'start_time' => (string) $row['start_time'], 'end_time' => (string) $row['end_time'], 'day_of_week' => (int) $row['day_of_week'], ]; } /** * Get latest schedule for class on given day where start_time <= time (may already be ended). * Uses lesson_slots/users as source of truth. ORDER BY start_time DESC, LIMIT 1. * * @param int $classId * @param int $dayOfWeek * @param string $time Time in H:i:s format * @return array{id: int, class_id: int, subject_id: int, teacher_user_id: int|null, teacher_name: string, room: string|null, start_time: string, end_time: string, day_of_week: int}|null */ public function getLatestScheduleForClassToday(int $classId, int $dayOfWeek, string $time): ?array { $db = \Config\Database::connect(); $sql = 'SELECT sch.id AS id, sch.class_id, sch.subject_id, sch.teacher_user_id, ' . 'COALESCE(u.name, sch.teacher_name) AS teacher_name, sch.room, ' . 'COALESCE(ls.start_time, sch.start_time) AS start_time, COALESCE(ls.end_time, sch.end_time) AS end_time, sch.day_of_week ' . 'FROM schedules sch ' . 'LEFT JOIN lesson_slots ls ON ls.id = sch.lesson_slot_id ' . 'LEFT JOIN users u ON u.id = sch.teacher_user_id ' . 'WHERE sch.class_id = ? AND sch.day_of_week = ? ' . 'AND ( COALESCE(ls.start_time, sch.start_time) ) <= ? ' . 'ORDER BY ( COALESCE(ls.start_time, sch.start_time) ) DESC ' . 'LIMIT 1'; $row = $db->query($sql, [$classId, $dayOfWeek, $time])->getRowArray(); if ($row === null) { return null; } return [ 'id' => (int) $row['id'], 'class_id' => (int) $row['class_id'], 'subject_id' => (int) $row['subject_id'], 'teacher_user_id' => isset($row['teacher_user_id']) ? (int) $row['teacher_user_id'] : null, 'teacher_name' => (string) ($row['teacher_name'] ?? ''), 'room' => isset($row['room']) ? (string) $row['room'] : null, 'start_time' => (string) $row['start_time'], 'end_time' => (string) $row['end_time'], 'day_of_week' => (int) $row['day_of_week'], ]; } /** * Get one schedule row by id with lesson_slots and users as source of truth. * * @param int $scheduleId * @return array{id: int, class_id: int, subject_id: int, teacher_user_id: int|null, teacher_name: string, start_time: string, end_time: string, day_of_week: int, room: string|null}|null */ public function getScheduleWithSlot(int $scheduleId): ?array { $db = \Config\Database::connect(); $sql = 'SELECT sch.id AS id, sch.class_id, sch.subject_id, sch.teacher_user_id, ' . 'COALESCE(u.name, sch.teacher_name) AS teacher_name, ' . 'COALESCE(ls.start_time, sch.start_time) AS start_time, COALESCE(ls.end_time, sch.end_time) AS end_time, ' . 'sch.day_of_week, sch.room ' . 'FROM schedules sch ' . 'LEFT JOIN lesson_slots ls ON ls.id = sch.lesson_slot_id ' . 'LEFT JOIN users u ON u.id = sch.teacher_user_id ' . 'WHERE sch.id = ? LIMIT 1'; $row = $db->query($sql, [$scheduleId])->getRowArray(); if ($row === null) { return null; } return [ 'id' => (int) $row['id'], 'class_id' => (int) $row['class_id'], 'subject_id' => (int) $row['subject_id'], 'teacher_user_id' => isset($row['teacher_user_id']) ? (int) $row['teacher_user_id'] : null, 'teacher_name' => (string) ($row['teacher_name'] ?? ''), 'start_time' => (string) $row['start_time'], 'end_time' => (string) $row['end_time'], 'day_of_week' => (int) $row['day_of_week'], 'room' => isset($row['room']) ? (string) $row['room'] : null, ]; } }