db = \Config\Database::connect(); $this->model = new PatientModel(); $this->rules = [ 'PatientID' => 'required|regex_match[/^[A-Za-z0-9.-]+$/]|max_length[30]', 'AlternatePID' => 'permit_empty|regex_match[/^[A-Za-z0-9.-]+$/]|max_length[30]', 'Prefix' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[10]', 'Sex' => 'required', 'NameFirst' => 'required|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameMiddle' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameMaiden' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameLast' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'Suffix' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[10]', 'PlaceOfBirth' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[100]', 'Citizenship' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[100]', 'Street_1' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'Street_2' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'Street_3' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'EmailAddress1' => 'permit_empty|valid_email|max_length[100]', 'EmailAddress2' => 'permit_empty|valid_email|max_length[100]', 'Birthdate' => 'required', 'PatIdt.IdentifierType' => 'permit_empty', 'PatIdt.Identifier' => 'permit_empty|max_length[255]', 'ZIP' => 'permit_empty|is_natural|max_length[10]', 'Phone' => 'permit_empty|regex_match[/^\\+?[0-9]{8,15}$/]', 'MobilePhone' => 'permit_empty|regex_match[/^\\+?[0-9]{8,15}$/]' ]; } public function index() { $filters = [ 'InternalPID' => $this->request->getVar('InternalPID'), 'PatientID' => $this->request->getVar('PatientID'), 'Name' => $this->request->getVar('Name'), 'Birthdate' => $this->request->getVar('Birthdate'), ]; try { $rows = $this->model->getPatients($filters); $rows = ValueSet::transformLabels($rows, [ 'Sex' => 'sex', ]); return $this->respond([ 'status' => 'success', 'message'=> "data fetched successfully", 'data' => $rows ], 200); } catch (\Exception $e) { return $this->failServerError('Exception : '.$e->getMessage()); } } public function show($InternalPID = null) { try { $row = $this->model->getPatient($InternalPID); if (empty($row)) { return $this->respond([ 'status' => 'success', 'message' => "data not found.", 'data' => null ], 200); } $row = ValueSet::transformLabels([$row], [ 'Sex' => 'sex', ])[0]; return $this->respond([ 'status' => 'success', 'message' => "data fetched successfully", 'data' => $row ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } public function create() { $input = $this->request->getJSON(true); // Khusus untuk Override PATIDT $type = $input['PatIdt']['IdentifierType'] ?? null; $identifierRulesMap = $this->getPatIdtIdentifierRulesMap(); if ($type === null || $type === '' || !is_string($type)) { $identifierRule = 'permit_empty|max_length[255]'; $this->rules['PatIdt.IdentifierType'] = 'permit_empty'; $this->rules['PatIdt.Identifier'] = $identifierRule; } else { $identifierRule = $identifierRulesMap[$type] ?? 'permit_empty|max_length[255]'; $this->rules['PatIdt.IdentifierType'] = 'required'; $this->rules['PatIdt.Identifier'] = $identifierRule; } if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); } try { $InternalPID = $this->model->createPatient($input); return $this->respondCreated([ 'status' => 'success', 'message' => "data $InternalPID created successfully" ]); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } public function update($InternalPID = null) { $input = $this->request->getJSON(true) ?? []; if (!$InternalPID || !ctype_digit((string) $InternalPID)) { return $this->respond([ 'status' => 'error', 'message' => 'InternalPID is required and must be a valid integer.' ], 400); } if (!is_array($input) || $input === []) { return $this->respond([ 'status' => 'failed', 'message' => 'Patch payload is required.' ], 400); } if (array_key_exists('PatIdt', $input) && $input['PatIdt'] !== null && !is_array($input['PatIdt'])) { return $this->failValidationErrors([ 'PatIdt' => 'PatIdt must be an object or null.' ]); } $patchRules = $this->buildPatchRules($input); if ($patchRules !== [] && !$this->validateData($input, $patchRules)) { return $this->failValidationErrors($this->validator->getErrors()); } try { $updatedPid = $this->model->updatePatientPartial((int) $InternalPID, $input); if ($updatedPid === null) { return $this->respond([ 'status' => 'failed', 'message' => "data $InternalPID not found" ], 404); } return $this->respond([ 'status' => 'success', 'message' => "data $updatedPid update successfully" ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } private function buildPatchRules(array $input): array { $rules = []; $fieldRules = [ 'PatientID' => 'permit_empty|regex_match[/^[A-Za-z0-9.-]+$/]|max_length[30]', 'AlternatePID' => 'permit_empty|regex_match[/^[A-Za-z0-9.-]+$/]|max_length[30]', 'Prefix' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[10]', 'Sex' => 'permit_empty', 'NameFirst' => 'required|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameMiddle' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameMaiden' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'NameLast' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|min_length[1]|max_length[60]', 'Suffix' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[10]', 'PlaceOfBirth' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[100]', 'Citizenship' => 'permit_empty|regex_match[/^[A-Za-z\'\. ]+$/]|max_length[100]', 'Street_1' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'Street_2' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'Street_3' => 'permit_empty|regex_match[/^[A-Za-z0-9\'.,\/\- ]+$/]|max_length[255]', 'EmailAddress1' => 'permit_empty|valid_email|max_length[100]', 'EmailAddress2' => 'permit_empty|valid_email|max_length[100]', 'Birthdate' => 'permit_empty', 'ZIP' => 'permit_empty|is_natural|max_length[10]', 'Phone' => 'permit_empty|regex_match[/^\\+?[0-9]{8,15}$/]', 'MobilePhone' => 'permit_empty|regex_match[/^\\+?[0-9]{8,15}$/]', 'Country' => 'permit_empty|max_length[10]', 'Race' => 'permit_empty|max_length[100]', 'MaritalStatus' => 'permit_empty', 'Religion' => 'permit_empty|max_length[100]', 'Ethnic' => 'permit_empty|max_length[100]', 'isDead' => 'permit_empty', 'TimeOfDeath' => 'permit_empty', 'PatCom' => 'permit_empty|string', 'PatAtt' => 'permit_empty', 'LinkTo' => 'permit_empty', 'Custodian' => 'permit_empty', ]; foreach ($fieldRules as $field => $rule) { if (array_key_exists($field, $input) && $field !== 'PatIdt') { $rules[$field] = $rule; } } if (array_key_exists('PatIdt', $input) && $input['PatIdt'] !== null) { $type = $input['PatIdt']['IdentifierType'] ?? null; $identifierRulesMap = $this->getPatIdtIdentifierRulesMap(); $identifierRule = is_string($type) ? ($identifierRulesMap[$type] ?? 'required|max_length[255]') : 'required|max_length[255]'; $rules['PatIdt.IdentifierType'] = 'required'; $rules['PatIdt.Identifier'] = $identifierRule; } return $rules; } private function getPatIdtIdentifierRulesMap(): array { return [ 'KTP' => 'required|regex_match[/^[0-9]{16}$/]', 'PASS' => 'required|regex_match[/^[A-Za-z0-9]{1,9}$/]', 'SSN' => 'required|regex_match[/^[0-9]{9}$/]', 'SIM' => 'required|regex_match[/^[0-9]{19,20}$/]', 'KTAS' => 'required|regex_match[/^[0-9]{11}$/]', ]; } public function delete() { try { $input = $this->request->getJSON(true); $InternalPID = $input["InternalPID"]; // Mencegah Inputan 0, [], null, sql injection if (empty($InternalPID) || !ctype_digit((string) $InternalPID)) { return $this->respond([ 'status' => 'error', 'message' => "Patient ID must be a valid integer." ], 400); } $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRow(); if (!$patient) { return $this->failNotFound("Patient ID with {$InternalPID} not found."); } $this->db->table('patient')->where('InternalPID', $InternalPID)->update(['DelDate' => date('Y-m-d H:i:s')]); return $this->respondDeleted([ 'status' => 'success', 'message' => "Patient ID with {$InternalPID} deleted successfully." ]); } catch (\Exception $e) { return $this->failServerError("Internal server error: " . $e->getMessage()); } } public function patientCheck() { try { $PatientID = $this->request->getVar('PatientID'); $EmailAddress = $this->request->getVar('EmailAddress'); $EmailAddress1 = $this->request->getVar('EmailAddress1'); $EmailAddress2 = $this->request->getVar('EmailAddress2'); $Phone = $this->request->getVar('Phone'); if (!empty($PatientID)){ if (!preg_match('/^[A-Za-z0-9.-]+$/', (string) $PatientID)) { return $this->respond([ 'status' => 'error', 'message' => 'PatientID format is invalid.', 'data' => null ], 400); } $patient = $this->db->table('patient') ->where('PatientID', $PatientID) ->get() ->getRowArray(); } elseif (!empty($EmailAddress) || !empty($EmailAddress1) || !empty($EmailAddress2)){ $searchEmail = $EmailAddress ?: $EmailAddress1 ?: $EmailAddress2; $patient = $this->db->table('patient') ->groupStart() ->where('EmailAddress1', $searchEmail) ->orWhere('EmailAddress2', $searchEmail) ->groupEnd() ->get() ->getRowArray(); } elseif (!empty($Phone)){ $patient = $this->db->table('patient') ->groupStart() ->where('Phone', $Phone) ->orWhere('MobilePhone', $Phone) ->groupEnd() ->get() ->getRowArray(); } else { return $this->respond([ 'status' => 'error', 'message' => 'PatientID, EmailAddress, or Phone parameter is required.', 'data' => null ], 400); } if (!$patient) { return $this->respond([ 'status' => 'success', 'message' => !empty($PatientID) ? 'PatientID not found.' : (!empty($Phone) ? 'Phone not found.' : 'EmailAddress not found.'), 'data' => true, ], 200); } return $this->respond([ 'status' => 'success', 'message' => !empty($PatientID) ? 'PatientID already exists.' : (!empty($Phone) ? 'Phone already exists.' : 'EmailAddress already exists.'), 'data' => false, ], 200); } catch (\Exception $e) { // Error Server Mengembalikan 500 return $this->failServerError('Something went wrong.'.$e->getMessage()); } } }