init backend presensi
This commit is contained in:
271
app/Modules/Dashboard/Services/DashboardScheduleService.php
Normal file
271
app/Modules/Dashboard/Services/DashboardScheduleService.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Dashboard\Services;
|
||||
|
||||
use App\Modules\Auth\Entities\Role;
|
||||
|
||||
/**
|
||||
* Dashboard Schedule Service
|
||||
*
|
||||
* Returns today's schedules filtered by user role (Asia/Jakarta).
|
||||
*/
|
||||
class DashboardScheduleService
|
||||
{
|
||||
/**
|
||||
* Get today's day_of_week (1=Monday, 7=Sunday) in Asia/Jakarta.
|
||||
*/
|
||||
public function getTodayDayOfWeek(): int
|
||||
{
|
||||
$tz = new \DateTimeZone('Asia/Jakarta');
|
||||
$now = new \DateTimeImmutable('now', $tz);
|
||||
return (int) $now->format('N');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get schedules for today filtered by user role.
|
||||
* Uses lesson_slots for start/end time and users for teacher_name; fallback to schedule columns when NULL.
|
||||
*
|
||||
* @param array|null $userContext { id, roles: [ { role_code } ] }
|
||||
* @return list<array{schedule_id: int, subject_name: string, class_name: string, teacher_name: string, start_time: string, end_time: string}>
|
||||
*/
|
||||
public function getSchedulesToday(?array $userContext = null): array
|
||||
{
|
||||
$dayOfWeek = $this->getTodayDayOfWeek();
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$builder = $db->table('schedules AS sch');
|
||||
$builder->select('
|
||||
sch.id AS schedule_id,
|
||||
COALESCE(sub.name, "-") AS subject_name,
|
||||
COALESCE(c.name, "-") AS class_name,
|
||||
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
|
||||
');
|
||||
$builder->join('lesson_slots AS ls', 'ls.id = sch.lesson_slot_id', 'left');
|
||||
$builder->join('users AS u', 'u.id = sch.teacher_user_id', 'left');
|
||||
$builder->join('subjects AS sub', 'sub.id = sch.subject_id', 'left');
|
||||
$builder->join('classes AS c', 'c.id = sch.class_id', 'left');
|
||||
$builder->where('sch.day_of_week', $dayOfWeek);
|
||||
$builder->orderBy('COALESCE(ls.start_time, sch.start_time)', 'ASC', false);
|
||||
|
||||
$this->applyRoleFilter($builder, $userContext);
|
||||
|
||||
$rows = $builder->get()->getResultArray();
|
||||
|
||||
$out = [];
|
||||
foreach ($rows as $row) {
|
||||
$out[] = [
|
||||
'schedule_id' => (int) $row['schedule_id'],
|
||||
'subject_name' => (string) ($row['subject_name'] ?? '-'),
|
||||
'class_name' => (string) ($row['class_name'] ?? '-'),
|
||||
'teacher_name' => (string) ($row['teacher_name'] ?? '-'),
|
||||
'start_time' => (string) $row['start_time'],
|
||||
'end_time' => (string) $row['end_time'],
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get schedules for a given date (day_of_week from date in Asia/Jakarta). Same shape as getSchedulesToday.
|
||||
*
|
||||
* @param string $dateYmd Y-m-d
|
||||
* @param array|null $userContext
|
||||
* @return list<array{schedule_id: int, subject_name: string, class_name: string, teacher_name: string, start_time: string, end_time: string}>
|
||||
*/
|
||||
public function getSchedulesByDate(string $dateYmd, ?array $userContext = null): array
|
||||
{
|
||||
$tz = new \DateTimeZone('Asia/Jakarta');
|
||||
$date = new \DateTimeImmutable($dateYmd . ' 12:00:00', $tz);
|
||||
$dayOfWeek = (int) $date->format('N');
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$builder = $db->table('schedules AS sch');
|
||||
$builder->select('
|
||||
sch.id AS schedule_id,
|
||||
COALESCE(sub.name, "-") AS subject_name,
|
||||
COALESCE(c.name, "-") AS class_name,
|
||||
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
|
||||
');
|
||||
$builder->join('lesson_slots AS ls', 'ls.id = sch.lesson_slot_id', 'left');
|
||||
$builder->join('users AS u', 'u.id = sch.teacher_user_id', 'left');
|
||||
$builder->join('subjects AS sub', 'sub.id = sch.subject_id', 'left');
|
||||
$builder->join('classes AS c', 'c.id = sch.class_id', 'left');
|
||||
$builder->where('sch.day_of_week', $dayOfWeek);
|
||||
$builder->orderBy('COALESCE(ls.start_time, sch.start_time)', 'ASC', false);
|
||||
|
||||
$this->applyRoleFilter($builder, $userContext);
|
||||
|
||||
$rows = $builder->get()->getResultArray();
|
||||
|
||||
$out = [];
|
||||
foreach ($rows as $row) {
|
||||
$out[] = [
|
||||
'schedule_id' => (int) $row['schedule_id'],
|
||||
'subject_name' => (string) ($row['subject_name'] ?? '-'),
|
||||
'class_name' => (string) ($row['class_name'] ?? '-'),
|
||||
'teacher_name' => (string) ($row['teacher_name'] ?? '-'),
|
||||
'start_time' => (string) $row['start_time'],
|
||||
'end_time' => (string) $row['end_time'],
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current lesson (schedule active right now) or next upcoming today.
|
||||
* Uses Asia/Jakarta. Same RBAC as getSchedulesToday. lesson_slots/users as source of truth with fallback.
|
||||
*
|
||||
* @param array|null $userContext
|
||||
* @return array{is_active_now: bool, schedule_id?: int, subject_name?: string, class_name?: string, teacher_name?: string, start_time?: string, end_time?: string, next_schedule?: array}
|
||||
*/
|
||||
public function getCurrentSchedule(?array $userContext = null): array
|
||||
{
|
||||
$tz = new \DateTimeZone('Asia/Jakarta');
|
||||
$now = new \DateTimeImmutable('now', $tz);
|
||||
$dayOfWeek = (int) $now->format('N');
|
||||
$currentTime = $now->format('H:i:s');
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$base = 'sch.id AS schedule_id, sch.class_id AS class_id, COALESCE(sub.name, "-") AS subject_name, COALESCE(c.name, "-") AS class_name, '
|
||||
. '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';
|
||||
$timeRangeWhere = '( COALESCE(ls.start_time, sch.start_time) <= ' . $db->escape($currentTime)
|
||||
. ' AND COALESCE(ls.end_time, sch.end_time) > ' . $db->escape($currentTime) . ' )';
|
||||
|
||||
$builder = $db->table('schedules AS sch');
|
||||
$builder->select($base);
|
||||
$builder->join('lesson_slots AS ls', 'ls.id = sch.lesson_slot_id', 'left');
|
||||
$builder->join('users AS u', 'u.id = sch.teacher_user_id', 'left');
|
||||
$builder->join('subjects AS sub', 'sub.id = sch.subject_id', 'left');
|
||||
$builder->join('classes AS c', 'c.id = sch.class_id', 'left');
|
||||
$builder->where('sch.day_of_week', $dayOfWeek);
|
||||
$builder->where($timeRangeWhere);
|
||||
$builder->orderBy('COALESCE(ls.start_time, sch.start_time)', 'ASC', false);
|
||||
$builder->limit(1);
|
||||
|
||||
$this->applyRoleFilter($builder, $userContext);
|
||||
|
||||
$rows = $builder->get()->getResultArray();
|
||||
|
||||
if (!empty($rows)) {
|
||||
$row = $rows[0];
|
||||
return [
|
||||
'is_active_now' => true,
|
||||
'schedule_id' => (int) $row['schedule_id'],
|
||||
'class_id' => (int) ($row['class_id'] ?? 0),
|
||||
'subject_name' => (string) ($row['subject_name'] ?? '-'),
|
||||
'class_name' => (string) ($row['class_name'] ?? '-'),
|
||||
'teacher_name' => (string) ($row['teacher_name'] ?? '-'),
|
||||
'start_time' => (string) $row['start_time'],
|
||||
'end_time' => (string) $row['end_time'],
|
||||
];
|
||||
}
|
||||
|
||||
$nextTimeWhere = '( COALESCE(ls.start_time, sch.start_time) > ' . $db->escape($currentTime) . ' )';
|
||||
$nextBuilder = $db->table('schedules AS sch');
|
||||
$nextBuilder->select($base);
|
||||
$nextBuilder->join('lesson_slots AS ls', 'ls.id = sch.lesson_slot_id', 'left');
|
||||
$nextBuilder->join('users AS u', 'u.id = sch.teacher_user_id', 'left');
|
||||
$nextBuilder->join('subjects AS sub', 'sub.id = sch.subject_id', 'left');
|
||||
$nextBuilder->join('classes AS c', 'c.id = sch.class_id', 'left');
|
||||
$nextBuilder->where('sch.day_of_week', $dayOfWeek);
|
||||
$nextBuilder->where($nextTimeWhere);
|
||||
$nextBuilder->orderBy('COALESCE(ls.start_time, sch.start_time)', 'ASC', false);
|
||||
$nextBuilder->limit(1);
|
||||
|
||||
$this->applyRoleFilter($nextBuilder, $userContext);
|
||||
|
||||
$nextRows = $nextBuilder->get()->getResultArray();
|
||||
$nextSchedule = null;
|
||||
if (!empty($nextRows)) {
|
||||
$r = $nextRows[0];
|
||||
$nextSchedule = [
|
||||
'schedule_id' => (int) $r['schedule_id'],
|
||||
'subject_name' => (string) ($r['subject_name'] ?? '-'),
|
||||
'class_name' => (string) ($r['class_name'] ?? '-'),
|
||||
'teacher_name' => (string) ($r['teacher_name'] ?? '-'),
|
||||
'start_time' => (string) $r['start_time'],
|
||||
'end_time' => (string) $r['end_time'],
|
||||
];
|
||||
}
|
||||
|
||||
$result = ['is_active_now' => false];
|
||||
if ($nextSchedule !== null) {
|
||||
$result['next_schedule'] = $nextSchedule;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function applyRoleFilter($builder, ?array $userContext): void
|
||||
{
|
||||
if ($userContext === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roles = $userContext['roles'] ?? [];
|
||||
$codes = array_column($roles, 'role_code');
|
||||
$userId = (int) ($userContext['id'] ?? 0);
|
||||
|
||||
if (in_array(Role::CODE_ADMIN, $codes, true) || in_array(Role::CODE_GURU_BK, $codes, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array(Role::CODE_WALI_KELAS, $codes, true)) {
|
||||
$classIds = $this->getClassIdsForWali($userId);
|
||||
if ($classIds === []) {
|
||||
$builder->where('1 =', 0);
|
||||
return;
|
||||
}
|
||||
$builder->whereIn('sch.class_id', $classIds);
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array(Role::CODE_GURU_MAPEL, $codes, true)) {
|
||||
$builder->where('sch.teacher_user_id', $userId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array(Role::CODE_ORANG_TUA, $codes, true)) {
|
||||
$studentIds = $this->getStudentIdsForParent($userId);
|
||||
if ($studentIds === []) {
|
||||
$builder->where('1 =', 0);
|
||||
return;
|
||||
}
|
||||
$db = \Config\Database::connect();
|
||||
$subQuery = $db->table('students')->select('class_id')->whereIn('id', $studentIds)->get()->getResultArray();
|
||||
$classIds = array_values(array_unique(array_map('intval', array_column($subQuery, 'class_id'))));
|
||||
if ($classIds === []) {
|
||||
$builder->where('1 =', 0);
|
||||
return;
|
||||
}
|
||||
$builder->whereIn('sch.class_id', $classIds);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getClassIdsForWali(int $userId): array
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$rows = $db->table('classes')->select('id')->where('wali_user_id', $userId)->get()->getResultArray();
|
||||
return array_map('intval', array_column($rows, 'id'));
|
||||
}
|
||||
|
||||
protected function getStudentIdsForParent(int $userId): array
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$rows = $db->table('student_parents AS sp')
|
||||
->select('sp.student_id')
|
||||
->join('parents AS p', 'p.id = sp.parent_id', 'inner')
|
||||
->where('p.user_id', $userId)
|
||||
->get()
|
||||
->getResultArray();
|
||||
return array_map('intval', array_column($rows, 'student_id'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user