150 lines
5.8 KiB
PHP
150 lines
5.8 KiB
PHP
<?php
|
||
|
||
namespace App\Modules\Academic\Controllers;
|
||
|
||
use App\Core\BaseApiController;
|
||
use App\Modules\Academic\Models\LessonSlotModel;
|
||
use App\Modules\Academic\Models\ScheduleModel;
|
||
use CodeIgniter\HTTP\ResponseInterface;
|
||
|
||
/**
|
||
* Weekly Schedule Management API (ADMIN only).
|
||
*/
|
||
class ScheduleManagementController extends BaseApiController
|
||
{
|
||
protected ScheduleModel $scheduleModel;
|
||
protected LessonSlotModel $lessonSlotModel;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->scheduleModel = new ScheduleModel();
|
||
$this->lessonSlotModel = new LessonSlotModel();
|
||
}
|
||
|
||
/**
|
||
* GET /api/academic/schedules/class/{classId}
|
||
* Returns weekly schedule grid: slots with days 1–5, each cell schedule or null.
|
||
*/
|
||
public function getByClass($classId): ResponseInterface
|
||
{
|
||
$classId = (int) $classId;
|
||
$slots = $this->lessonSlotModel->where('is_active', 1)->orderBy('slot_number', 'ASC')->findAll();
|
||
$rows = $this->scheduleModel->where('class_id', $classId)->findAll();
|
||
|
||
$bySlotDay = [];
|
||
foreach ($rows as $row) {
|
||
$slotId = $row->lesson_slot_id ?? 0;
|
||
$day = (int) $row->day_of_week;
|
||
if ($slotId && $day >= 1 && $day <= 7) {
|
||
$bySlotDay[$slotId][$day] = $this->scheduleToArray($row);
|
||
}
|
||
}
|
||
|
||
$grid = [];
|
||
foreach ($slots as $slot) {
|
||
$slotId = (int) $slot->id;
|
||
$days = [];
|
||
for ($d = 1; $d <= 5; $d++) {
|
||
$days[$d] = $bySlotDay[$slotId][$d] ?? null;
|
||
}
|
||
$grid[] = [
|
||
'lesson_slot_id' => $slotId,
|
||
'slot_number' => (int) $slot->slot_number,
|
||
'start_time' => (string) $slot->start_time,
|
||
'end_time' => (string) $slot->end_time,
|
||
'days' => $days,
|
||
];
|
||
}
|
||
|
||
return $this->successResponse($grid, 'Weekly schedule');
|
||
}
|
||
|
||
/**
|
||
* POST /api/academic/schedules/bulk-save
|
||
* Body: { class_id, schedules: [ { day_of_week, lesson_slot_id, subject_id, teacher_user_id [, room] }, ... ] }
|
||
* Deletes existing schedules for class then inserts new ones in a transaction.
|
||
*/
|
||
public function bulkSave(): ResponseInterface
|
||
{
|
||
$input = $this->request->getJSON(true) ?? [];
|
||
$classId = (int) ($input['class_id'] ?? 0);
|
||
$items = $input['schedules'] ?? [];
|
||
|
||
if ($classId <= 0) {
|
||
return $this->errorResponse('class_id is required and must be positive', null, null, 422);
|
||
}
|
||
|
||
if (!is_array($items)) {
|
||
return $this->errorResponse('schedules must be an array', null, null, 422);
|
||
}
|
||
|
||
$db = \Config\Database::connect();
|
||
$db->transStart();
|
||
|
||
try {
|
||
$this->scheduleModel->where('class_id', $classId)->delete();
|
||
$this->scheduleModel->skipValidation(true);
|
||
foreach ($items as $item) {
|
||
$day = (int) ($item['day_of_week'] ?? 0);
|
||
$slot = (int) ($item['lesson_slot_id'] ?? 0);
|
||
$subj = (int) ($item['subject_id'] ?? 0);
|
||
$teacher = (int) ($item['teacher_user_id'] ?? 0);
|
||
if ($day < 1 || $day > 7 || $slot <= 0 || $subj <= 0) {
|
||
$db->transRollback();
|
||
return $this->errorResponse('Each schedule must have day_of_week (1-7), lesson_slot_id, subject_id', null, null, 422);
|
||
}
|
||
$data = [
|
||
'class_id' => $classId,
|
||
'subject_id' => $subj,
|
||
'teacher_user_id' => $teacher ?: null,
|
||
'lesson_slot_id' => $slot,
|
||
'day_of_week' => $day,
|
||
'room' => isset($item['room']) ? (string) $item['room'] : null,
|
||
'is_active' => 1,
|
||
];
|
||
if ($this->scheduleModel->insert($data) === false) {
|
||
$db->transRollback();
|
||
return $this->errorResponse('Failed to insert schedule', null, null, 422);
|
||
}
|
||
}
|
||
$this->scheduleModel->skipValidation(false);
|
||
$db->transComplete();
|
||
} catch (\Throwable $e) {
|
||
if ($db->transStatus() === false) {
|
||
$db->transRollback();
|
||
}
|
||
return $this->errorResponse($e->getMessage(), null, null, 500);
|
||
}
|
||
|
||
if ($db->transStatus() === false) {
|
||
return $this->errorResponse('Database transaction failed', null, null, 500);
|
||
}
|
||
|
||
return $this->successResponse(null, 'Schedules saved');
|
||
}
|
||
|
||
protected function scheduleToArray($schedule): array
|
||
{
|
||
if (is_array($schedule)) {
|
||
return [
|
||
'id' => (int) ($schedule['id'] ?? 0),
|
||
'class_id' => (int) ($schedule['class_id'] ?? 0),
|
||
'subject_id' => (int) ($schedule['subject_id'] ?? 0),
|
||
'teacher_user_id' => isset($schedule['teacher_user_id']) ? (int) $schedule['teacher_user_id'] : null,
|
||
'lesson_slot_id' => (int) ($schedule['lesson_slot_id'] ?? 0),
|
||
'day_of_week' => (int) ($schedule['day_of_week'] ?? 0),
|
||
'room' => isset($schedule['room']) ? (string) $schedule['room'] : null,
|
||
];
|
||
}
|
||
return [
|
||
'id' => (int) $schedule->id,
|
||
'class_id' => (int) $schedule->class_id,
|
||
'subject_id' => (int) $schedule->subject_id,
|
||
'teacher_user_id' => $schedule->teacher_user_id !== null ? (int) $schedule->teacher_user_id : null,
|
||
'lesson_slot_id' => (int) $schedule->lesson_slot_id,
|
||
'day_of_week' => (int) $schedule->day_of_week,
|
||
'room' => $schedule->room !== null ? (string) $schedule->room : null,
|
||
];
|
||
}
|
||
}
|