db = \Config\Database::connect(); $this->rulesPatient = [ 'PatientID' => 'required|is_unique[patient.PatientID]|max_length[50]', 'AlternatePID' => 'permit_empty|max_length[50]', 'NameFirst' => 'required|min_length[1]|max_length[255]', 'EmailAddress1' => 'required|is_unique[patient.EmailAddress1]', 'Gender' => 'required' ]; $this->rulesPatIdt = ['Identifier' => 'required|is_unique[patidt.Identifier]']; } // OK - Done public function index() { try { $InternalPID = $this->request->getVar('InternalPID'); $PatientID = $this->request->getVar('PatientID'); $Name = $this->request->getVar('Name'); $Birthdate = $this->request->getVar('Birthdate'); $qname = "LOWER(CONCAT_WS(' ', IFNULL(Prefix,''), IFNULL(NameFirst,''), IFNULL(NameMiddle,''), IFNULL(NameLast,''), IFNULL(NameMaiden,''), IFNULL(Suffix,'')))"; $builder = $this->db->table('patient'); $builder->select("InternalPID, PatientID, $qname as FullName, Gender, Birthdate, EmailAddress1 as Email, MobilePhone"); if ($Name !== null) { $sql = $qname; $rawSql = new RawSql($sql); $builder->like($rawSql, $Name, 'both'); } if ($InternalPID !== null) { $builder->where('InternalPID', $InternalPID); } if ($PatientID !== null) { $builder->like('PatientID', $PatientID, 'both'); } if ($Birthdate !== null) { $builder->where('Birthdate', $Birthdate); } $filteredPatients = $builder->get()->getResultArray(); // Data pasien tidak ada mengembalikan - success 200 if (empty($filteredPatients)) { return $this->respond([ 'status' => 'success', 'message' => 'No patient records found matching the criteria.', 'data' => [] ], 200); } // Data pasien ditemukan dan mengembalikan - success 200 return $this->respond([ 'status' => 'success', 'message'=> "Patients fetched successfully", 'data' => $filteredPatients, ], 200); } catch (\Exception $e) { // Error Server Mengembalikan 500 return $this->failServerError('Something went wrong.'.$e->getMessage()); } } public function show($InternalPID = null) { try { $rows = $this->db->table('patient') ->select(" patient.*, country.Country as CountryName, race.Race as RaceName, religion.Religion as ReligionName, ethnic.Ethnic as EthnicName, patcom.Comment as Comment, patidt.IdentifierType, patidt.Identifier, patatt.Address ") ->join('country', 'country.IntCountryID = patient.IntCountryID', 'left') ->join('race', 'race.RaceID = patient.RaceID', 'left') ->join('religion', 'religion.ReligionID = patient.ReligionID', 'left') ->join('ethnic', 'ethnic.EthnicID = patient.EthnicID', 'left') ->join('patcom', 'patcom.InternalPID = patient.InternalPID', 'left') ->join('patidt', 'patidt.InternalPID = patient.InternalPID', 'left') ->join('patatt', 'patatt.InternalPID = patient.InternalPID and patatt.DelDate is null', 'left') ->where('patient.InternalPID', (int) $InternalPID) ->get() ->getResultArray(); if (empty($rows)) { return $this->respond([ 'status' => 'success', 'message' => "Patient with ID {$InternalPID} not found.", 'data' => [], ], 200); } // Use first row as base patient data $patient = $rows[0]; $patient = $this->transformPatientData($patient); $patient['Identity'] = null; $patient['Attachments'] = []; foreach ($rows as $row) { if ($row['IdentifierType'] && $row['Identifier'] && !$patient['Identity']) { $patient['Identity'] = [ 'IdentifierType' => $row['IdentifierType'], 'Identifier' => $row['Identifier'], ]; } if ($row['Address']) { $patient['Attachments'][] = ['Address' => $row['Address']]; } } if (empty($patient['Identity'])) { $patient['Identity'] = null; } if (empty($patient['Attachments'])) { $patient['Attachments'] = null; } return $this->respond([ 'status' => 'success', 'message' => "Patient Show Successfully", 'data' => $patient, ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } private function transformPatientData(array $patient): array { $patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"]); $patient["Birthdate"] = $this->formatedDate($patient["Birthdate"]); $patient["CreateDate"] = $this->formatedDate($patient["CreateDate"]); $patient["DelDate"] = $this->formatedDate($patient["DelDate"]); $patient["DeathDateTime"] = $this->formatedDate($patient["DeathDateTime"]); $patient["BirthdateConversion"] = $this->formatedDateForDisplay($patient["Birthdate"]); $patient["LinkTo"] = $this->getLinkedPatients($patient['LinkTo']); $patient["Custodian"] = $this->getCustodian($patient['Custodian']); return $patient; } private function getLinkedPatients(?string $linkTo): ?array { if (empty($linkTo)) { return null; } $ids = array_filter(explode(',', $linkTo)); return $this->db->table('patient') ->select('InternalPID, PatientID') ->whereIn('InternalPID', $ids) ->get() ->getResultArray() ?: null; } private function getCustodian($custodianId): ?array { if (empty($custodianId)) { return null; } return $this->db->table('patient') ->select('InternalPID, PatientID') ->where('InternalPID', (int) $custodianId) ->get() ->getRowArray() ?: null; } public function create() { try { $input = $this->request->getJSON(true); // Prepare data $dataPatient = $this->preparePatientData($input); $dataPatidt = $this->preparePatidtData($input); $dataPatatt = $this->preparePatattData($input); $dataPatcom = $this->preparePatcomData($input); // Validation rules //$rulesPatidt = ['Identifier' => 'required|is_unique[patidt.Identifier]']; //$rulesPatatt = ['Address' => 'required|is_unique[patatt.Address]']; // Validate patient if (!$this->validateData($dataPatient, $this->rulesPatient)) { return $this->validationError('patient', $this->validator->getErrors()); } // Validate patidt if (!$this->validateData($dataPatidt, $this->rulesPatIdt)) { return $this->validationError('patidt', $this->validator->getErrors()); } /* Validate patatt (if exists, validate only the first row) if (!empty($dataPatatt) && !$this->validateData($dataPatatt[0], $rulesPatatt)) { return $this->validationError('patatt', $this->validator->getErrors()); } */ $this->db->transStart(); $this->db->table('patient')->insert($dataPatient); $newInternalPatientId = $this->db->insertID(); $dataPatidt['InternalPID'] = $newInternalPatientId; $this->db->table('patidt')->insert($dataPatidt); if (!empty($dataPatatt)) { foreach ($dataPatatt as &$row) { $row['InternalPID'] = $newInternalPatientId; } $this->db->table('patatt')->upsertBatch($dataPatatt); } if (!empty($dataPatcom['Comment'])) { $dataPatcom['InternalPID'] = $newInternalPatientId; $this->db->table('patcom')->insert($dataPatcom); } $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Insert patient failed: ' . $dbError['message']); } $this->db->transComplete(); if ($this->db->transStatus() === false) { $dbError = $this->db->error(); return $this->failServerError( 'Failed to create patient data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error') ); } return $this->respondCreated([ 'status' => 'success', 'message' => 'Patient created successfully', 'data' => $newInternalPatientId ], 201); } catch (\Exception $e) { $this->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } private function preparePatientData(array $input, string $mode = 'create'): array { $LinkTo = null; if (!empty($input['LinkTo'])) { $ids = array_column($input['LinkTo'], 'InternalPID'); $LinkTo = implode(',', $ids); } $data = [ "PatientID" => $input['PatientID'] ?? null, "AlternatePID" => $input['AlternatePID'] ?? null, "Prefix" => $input['Prefix'] ?? null, "NameFirst" => $input['NameFirst'] ?? null, "NameMiddle" => $input['NameMiddle'] ?? null, "NameMaiden" => $input['NameMaiden'] ?? null, "NameLast" => $input['NameLast'] ?? null, "Suffix" => $input['Suffix'] ?? null, "NameAlias" => $input['NameAlias'] ?? null, "Gender" => !empty($input['Gender']) ? (int)$input['Gender'] : null, "PlaceOfBirth" => $input['PlaceOfBirth'] ?? null, "Birthdate" => $input['Birthdate'] ?? null, "Street_1" => $input['Street_1'] ?? null, "Street_2" => $input['Street_2'] ?? null, "Street_3" => $input['Street_3'] ?? null, "City" => $input['City'] ?? null, "Province" => $input['Province'] ?? null, "ZIP" => $input['ZIP'] ?? null, "EmailAddress1" => $input['EmailAddress1'] ?? null, "EmailAddress2" => $input['EmailAddress2'] ?? null, "Phone" => $input['Phone'] ?? null, "MobilePhone" => $input['MobilePhone'] ?? null, "RaceID" => isset($input['RaceID']) ? (int)$input['RaceID'] : null, "IntCountryID" => isset($input['IntCountryID']) ? (int)$input['IntCountryID'] : null, "MaritalStatus" => $input['MaritalStatus'] ?? null, "ReligionID" => isset($input['ReligionID']) ? (int)$input['ReligionID'] : null, "EthnicID" => isset($input['EthnicID']) ? (int)$input['EthnicID'] : null, "Citizenship" => $input['Citizenship'] ?? null, "DeathIndicator" => isset($input['DeathIndicator']) ? (int)$input['DeathIndicator'] : null, "DeathDateTime" => $input['DeathDateTime'] ?? null, "Custodian" => isset($input['Custodian']) ? (int)$input['Custodian'] : null, "DelDate" => null, "LinkTo" => $LinkTo ]; if(!empty($input['InternalPID'])) { $data["InternalPID"] = $input["InternalPID"]; } return $data; } private function preparePatidtData(array $input ): array { $data = [ "IdentifierType" => $input['Identity']['IdentifierType'] ?? null, "Identifier" => $input['Identity']['Identifier'] ?? null, ]; return $data; } private function preparePatattData(array $input): array { if (empty($input['Attachments'])) { return []; } return array_map(function ($attachment) { $row = [ "Address" => $attachment['Address'] ?? null, ]; return $row; }, $input['Attachments']); } private function preparePatcomData(array $input): array { $data = [ "Comment" => $input['Comment'] ?? null, ]; return $data; } private function validationError(string $context, array $errors) { return $this->respond([ 'status' => 'error', 'message' => "Validation failed ({$context})", 'errors' => $errors ], 400); } public function update() { try { $input = $this->request->getJSON(true); if (!$input) { return $this->respond(['status' => 'error', 'message' => 'Invalid JSON input'], 400); } if (!$input["InternalPID"] || !is_numeric($input["InternalPID"])) { return $this->respond(['status' => 'error', 'message' => 'Invalid or missing InternalPID'], 400); } $InternalPID = $input["InternalPID"]; $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRowArray(); if (!$patient) { return $this->respond(['status' => 'error', 'message' => 'Patient not found'], 404); } $dataPatient = $this->preparePatientData($input); $dataPatIdt = $this->preparePatidtData($input); $dataPatCom = $this->preparePatcomData($input); $dataPatAtt = $this->preparePatattData($input); // Validasi if (!$this->validateData($dataPatient, $this->rulesPatient)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patient)', 'errors' => $this->validator->getErrors() ], 400); } if (!$this->validateData($dataPatIdt, $this->rulesPatIdt)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patidt)', 'errors' => $this->validator->getErrors() ], 400); } $this->db->transStart(); $this->db->table('patient')->where('InternalPID', $InternalPID)->update($dataPatient); $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Update patient failed: ' . $dbError['message']); } $this->db->table('patidt')->where('InternalPID', $InternalPID)->update($dataPatIdt); $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Update patidt failed: ' . $dbError['message']); } if (!empty($dataPatAtt)) { foreach ($dataPatAtt as &$row) { $row['InternalPID'] = $InternalPID; } $this->db->table('patatt')->upsertBatch($dataPatAtt); $addresses = array_column($dataPatAtt, 'Address'); $this->db->table('patatt')->where('InternalPID', $InternalPID)->WhereNotIn('Address', $addresses)->update(['DelDate' => date('Y-m-d H:i:s')]); } else { $this->db->table('patatt')->where('InternalPID', $InternalPID)->update(['DelDate' => date('Y-m-d H:i:s')]); } if(!empty($dataPatcom['Comment'])) { $dataPatcom['InternalPID'] = $InternalPID; $this->db->table('patcom')->upsert($dataPatCom); } $this->db->transComplete(); if ($this->db->transStatus() === false) { $dbError = $this->db->error(); return $this->failServerError('Failed to update patient data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown error')); } return $this->respond([ 'status' => 'success', 'message' => 'Patient updated successfully', 'data' => $dataPatient ], 200); } catch (\Exception $e) { $this->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } public function delete() { try { $input = $this->request->getJSON(true); $InternalPID = $input["InternalPID"]; if (!$InternalPID) { return $this->failValidationError('Patient ID is required.'); } $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()); } } // OK - Done public function patientCheck() { try { $PatientID = $this->request->getVar('PatientID'); $EmailAddress1 = $this->request->getVar('EmailAddress1'); if ($PatientID!=null){ $tableName = 'PatientID'; $searchName = $PatientID; } if ($EmailAddress1!=null){ $tableName = 'EmailAddress1'; $searchName = $EmailAddress1; } $patient = $this->db->table('patient') ->where($tableName, $searchName) ->get() ->getRowArray(); if (!$patient) { return $this->respond([ 'status' => 'success', 'message' => "$tableName not found.", 'data' => true, ], 200); } return $this->respond([ 'status' => 'success', 'message' => "$tableName already exists.", 'data' => false, ], 200); } catch (\Exception $e) { // Error Server Mengembalikan 500 return $this->failServerError('Something went wrong.'.$e->getMessage()); } } // Ubah ke format Years Months Days private function calculateAgeFromBirthdate($birthdate) { $dob = new \DateTime($birthdate); $today = new \DateTime(); $diff = $today->diff($dob); $formattedAge = ""; if ($diff->y > 0){ $formattedAge .= "{$diff->y} Years "; } if ($diff->m > 0){ $formattedAge .= "{$diff->m} Months "; } if ($diff->d > 0){ $formattedAge .= "{$diff->d} Days"; } return $formattedAge; } // Ubah ke format Y-m-d H:i private function formatedDate($dateString) { $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); if (!$date) { $timestamp = strtotime($dateString); if ($timestamp) { return date('Y-m-d H:i', $timestamp); } return null; } return $date->format('Y-m-d H:i'); } // Ubah ke format j M Y private function formatedDateForDisplay($dateString) { $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); if (!$date) { $timestamp = strtotime($dateString); if ($timestamp) { return date('j M Y', $timestamp); } return null; } return $date->format('j M Y'); } }