319 lines
14 KiB
PHP
Executable File
319 lines
14 KiB
PHP
Executable File
<?php
|
|
namespace App\Controllers\Patient;
|
|
|
|
use App\Traits\ResponseTrait;
|
|
use CodeIgniter\Controller;
|
|
use App\Libraries\ValueSet;
|
|
use App\Models\Patient\PatientModel;
|
|
|
|
class PatientController extends Controller {
|
|
use ResponseTrait;
|
|
|
|
protected $db;
|
|
protected $model;
|
|
protected $rules;
|
|
|
|
public function __construct() {
|
|
$this->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');
|
|
$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)) {
|
|
$patient = $this->db->table('patient')
|
|
->groupStart()
|
|
->where('EmailAddress1', $EmailAddress)
|
|
->orWhere('EmailAddress2', $EmailAddress)
|
|
->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());
|
|
}
|
|
}
|
|
}
|