init backend presensi
This commit is contained in:
195
app/Modules/Academic/Controllers/StudentController.php
Normal file
195
app/Modules/Academic/Controllers/StudentController.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Academic\Controllers;
|
||||
|
||||
use App\Core\BaseApiController;
|
||||
use App\Modules\Academic\Models\StudentModel;
|
||||
use App\Modules\Academic\Models\ClassModel;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Student CRUD API (ADMIN only).
|
||||
*/
|
||||
class StudentController extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* GET /api/academic/students
|
||||
* Query: class_id (optional), search (optional), unmapped_only (optional), page (default 1), per_page (default 25).
|
||||
*/
|
||||
public function index(): ResponseInterface
|
||||
{
|
||||
$classId = $this->request->getGet('class_id');
|
||||
$search = $this->request->getGet('search');
|
||||
$search = is_string($search) ? trim($search) : '';
|
||||
$unmappedOnly = $this->request->getGet('unmapped_only') === '1' || $this->request->getGet('unmapped_only') === 'true';
|
||||
$page = max(1, (int) ($this->request->getGet('page') ?? 1));
|
||||
$perPage = max(5, min(100, (int) ($this->request->getGet('per_page') ?? 20)));
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$builder = $db->table('students')
|
||||
->select('students.id, students.nisn, students.name, students.gender, students.class_id, students.is_active,
|
||||
classes.grade, classes.major, classes.name AS class_name')
|
||||
->join('classes', 'classes.id = students.class_id', 'left')
|
||||
->orderBy('students.name', 'ASC');
|
||||
|
||||
if ($unmappedOnly) {
|
||||
$builder->where('students.class_id', null);
|
||||
} elseif ($classId !== null && $classId !== '') {
|
||||
$builder->where('students.class_id', (int) $classId);
|
||||
}
|
||||
if ($search !== '') {
|
||||
$builder->groupStart()
|
||||
->like('students.name', $search)
|
||||
->orLike('students.nisn', $search)
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
$total = $builder->countAllResults(false);
|
||||
$rows = $builder->limit($perPage, ($page - 1) * $perPage)->get()->getResultArray();
|
||||
|
||||
$data = array_map(static function ($r) {
|
||||
$grade = $r['grade'] !== null ? trim((string) $r['grade']) : '';
|
||||
$major = $r['major'] !== null ? trim((string) $r['major']) : '';
|
||||
$cName = $r['class_name'] !== null ? trim((string) $r['class_name']) : '';
|
||||
$parts = array_filter([$grade, $major, $cName], static fn ($v) => $v !== '');
|
||||
$fullLabel = $parts !== [] ? implode(' ', $parts) : null;
|
||||
|
||||
return [
|
||||
'id' => (int) $r['id'],
|
||||
'nisn' => (string) $r['nisn'],
|
||||
'name' => (string) $r['name'],
|
||||
'gender' => $r['gender'] !== null ? (string) $r['gender'] : null,
|
||||
'class_id' => $r['class_id'] !== null ? (int) $r['class_id'] : null,
|
||||
'class_label' => $fullLabel,
|
||||
'is_active' => (int) ($r['is_active'] ?? 1),
|
||||
];
|
||||
}, $rows);
|
||||
|
||||
$totalPages = $total > 0 ? (int) ceil($total / $perPage) : 0;
|
||||
$meta = [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
];
|
||||
|
||||
return $this->successResponse($data, 'Students', $meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/academic/students
|
||||
*/
|
||||
public function create(): ResponseInterface
|
||||
{
|
||||
$payload = $this->request->getJSON(true) ?? [];
|
||||
$data = $this->payloadToStudentData($payload);
|
||||
|
||||
$model = new StudentModel();
|
||||
if (! $model->validate($data)) {
|
||||
return $this->errorResponse(
|
||||
implode(' ', $model->errors()),
|
||||
$model->errors(),
|
||||
null,
|
||||
ResponseInterface::HTTP_UNPROCESSABLE_ENTITY
|
||||
);
|
||||
}
|
||||
|
||||
$id = $model->insert($data);
|
||||
if ($id === false) {
|
||||
return $this->errorResponse('Gagal menyimpan siswa', null, null, ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$row = $model->find($id);
|
||||
return $this->successResponse($this->rowToResponse($row), 'Siswa berhasil ditambahkan', null, ResponseInterface::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/academic/students/{id}
|
||||
*/
|
||||
public function update(int $id): ResponseInterface
|
||||
{
|
||||
$model = new StudentModel();
|
||||
$row = $model->find($id);
|
||||
if (! $row) {
|
||||
return $this->errorResponse('Siswa tidak ditemukan', null, null, ResponseInterface::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$payload = $this->request->getJSON(true) ?? [];
|
||||
$data = $this->payloadToStudentData($payload, $row);
|
||||
|
||||
if (! $model->validate(array_merge(['id' => $id], $data))) {
|
||||
return $this->errorResponse(
|
||||
implode(' ', $model->errors()),
|
||||
$model->errors(),
|
||||
null,
|
||||
ResponseInterface::HTTP_UNPROCESSABLE_ENTITY
|
||||
);
|
||||
}
|
||||
|
||||
if ($model->update($id, $data) === false) {
|
||||
return $this->errorResponse('Gagal mengubah siswa', null, null, ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$updated = $model->find($id);
|
||||
return $this->successResponse($this->rowToResponse($updated), 'Siswa berhasil diubah');
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/academic/students/{id}
|
||||
*/
|
||||
public function delete(int $id): ResponseInterface
|
||||
{
|
||||
$model = new StudentModel();
|
||||
if (! $model->find($id)) {
|
||||
return $this->errorResponse('Siswa tidak ditemukan', null, null, ResponseInterface::HTTP_NOT_FOUND);
|
||||
}
|
||||
if ($model->delete($id) === false) {
|
||||
return $this->errorResponse('Gagal menghapus siswa', null, null, ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
return $this->successResponse(null, 'Siswa berhasil dihapus');
|
||||
}
|
||||
|
||||
private function payloadToStudentData(array $payload, $existing = null): array
|
||||
{
|
||||
$classId = isset($payload['class_id']) && $payload['class_id'] !== '' && $payload['class_id'] !== null
|
||||
? (int) $payload['class_id']
|
||||
: null;
|
||||
$gender = isset($payload['gender']) && in_array($payload['gender'], ['L', 'P'], true)
|
||||
? $payload['gender']
|
||||
: ($existing && isset($existing->gender) ? $existing->gender : null);
|
||||
$isActive = array_key_exists('is_active', $payload)
|
||||
? (int) (bool) $payload['is_active']
|
||||
: ($existing && isset($existing->is_active) ? (int) $existing->is_active : 1);
|
||||
|
||||
return [
|
||||
'nisn' => trim($payload['nisn'] ?? $existing->nisn ?? ''),
|
||||
'name' => trim($payload['name'] ?? $existing->name ?? ''),
|
||||
'gender' => $gender,
|
||||
'class_id' => $classId,
|
||||
'is_active'=> $isActive,
|
||||
];
|
||||
}
|
||||
|
||||
private function rowToResponse($row): array
|
||||
{
|
||||
$classId = $row->class_id ?? null;
|
||||
$classLabel = null;
|
||||
if ($classId !== null) {
|
||||
$classModel = new ClassModel();
|
||||
$c = $classModel->find($classId);
|
||||
if ($c) {
|
||||
$classLabel = trim($c->grade . ' ' . $c->major . ' ' . $c->name) ?: (string) $c->name;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (int) $row->id,
|
||||
'nisn' => (string) $row->nisn,
|
||||
'name' => (string) $row->name,
|
||||
'gender' => $row->gender !== null ? (string) $row->gender : null,
|
||||
'class_id' => $classId !== null ? (int) $classId : null,
|
||||
'class_label' => $classLabel,
|
||||
'is_active' => (int) ($row->is_active ?? 1),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user