clqms-be/app/Controllers/TestsController.php
mahdahar e36e390f71 refactor: consolidate ValueSet API and simplify seeders
- Consolidate ValueSet routes from multiple nested groups to flat structure
- Delete deprecated ValueSet\ namespaced controllers (ValueSetController, ValueSetDefController)
- Remove ValueSetSeeder and ValueSetCountrySeeder from DBSeeder
- Simplify seeders (LocationSeeder, OrganizationSeeder, PatientSeeder, TestSeeder)
  to use literal string values instead of ValueSet lookups
- Add new ValueSetController and ValueSetDefController in root namespace
- Update test files for new controller structure
The key changes are:
1. Routes: Consolidated from nested ValueSet\ namespace routes to flat ValueSetController routes with /items sub-endpoints
2. Controllers: Deleted old app/Controllers/ValueSet/ directory, created new root-level controllers
3. Seeders: Removed ValueSet dependencies, using literal values like 'ROOM', '1', 'TEST' instead of [12]['ROOM'] etc.
4. Tests: Updated tests to match new controller structure
2026-01-13 16:48:43 +07:00

620 lines
23 KiB
PHP

<?php
namespace App\Controllers;
use CodeIgniter\API\ResponseTrait;
use App\Controllers\BaseController;
use App\Libraries\ValueSet;
class TestsController extends BaseController
{
use ResponseTrait;
protected $db;
protected $rules;
protected $model;
protected $modelCal;
protected $modelTech;
protected $modelGrp;
protected $modelMap;
protected $modelRefNum;
protected $modelRefTxt;
public function __construct()
{
$this->db = \Config\Database::connect();
$this->model = new \App\Models\Test\TestDefSiteModel;
$this->modelCal = new \App\Models\Test\TestDefCalModel;
$this->modelTech = new \App\Models\Test\TestDefTechModel;
$this->modelGrp = new \App\Models\Test\TestDefGrpModel;
$this->modelMap = new \App\Models\Test\TestMapModel;
$this->modelRefNum = new \App\Models\RefRange\RefNumModel;
$this->modelRefTxt = new \App\Models\RefRange\RefTxtModel;
$this->rules = [
'TestSiteCode' => 'required|min_length[3]|max_length[6]',
'TestSiteName' => 'required',
'TestType' => 'required',
'SiteID' => 'required'
];
}
public function index()
{
$siteId = $this->request->getGet('SiteID');
$testType = $this->request->getGet('TestType');
$visibleScr = $this->request->getGet('VisibleScr');
$visibleRpt = $this->request->getGet('VisibleRpt');
$keyword = $this->request->getGet('TestSiteName');
$builder = $this->db->table('testdefsite')
->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate")
->where('testdefsite.EndDate IS NULL');
if ($siteId) {
$builder->where('testdefsite.SiteID', $siteId);
}
if ($testType) {
$builder->where('testdefsite.TestType', $testType);
}
if ($visibleScr !== null) {
$builder->where('testdefsite.VisibleScr', $visibleScr);
}
if ($visibleRpt !== null) {
$builder->where('testdefsite.VisibleRpt', $visibleRpt);
}
if ($keyword) {
$builder->like('testdefsite.TestSiteName', $keyword);
}
$rows = $builder->orderBy('testdefsite.SeqScr', 'ASC')->get()->getResultArray();
if (empty($rows)) {
return $this->respond(['status' => 'success', 'message' => "No data.", 'data' => []], 200);
}
$rows = ValueSet::transformLabels($rows, [
'TestType' => 'test_type',
]);
return $this->respond(['status' => 'success', 'message' => "Data fetched successfully", 'data' => $rows], 200);
}
public function show($id = null)
{
if (!$id)
return $this->failValidationErrors('TestSiteID is required');
$row = $this->model->select("testdefsite.*")
->where("testdefsite.TestSiteID", $id)
->find($id);
if (!$row) {
return $this->respond(['status' => 'success', 'message' => "No data.", 'data' => null], 200);
}
$row = ValueSet::transformLabels([$row], [
'TestType' => 'test_type',
])[0];
$typeCode = $row['TestType'] ?? '';
if ($typeCode === 'CALC') {
$row['testdefcal'] = $this->db->table('testdefcal')
->select('testdefcal.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdefcal.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdefcal.DepartmentID', 'left')
->where('testdefcal.TestSiteID', $id)
->where('testdefcal.EndDate IS NULL')
->get()->getResultArray();
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
} elseif ($typeCode === 'GROUP') {
$row['testdefgrp'] = $this->db->table('testdefgrp')
->select('testdefgrp.*, t.TestSiteCode, t.TestSiteName, t.TestType')
->join('testdefsite t', 't.TestSiteID=testdefgrp.Member', 'left')
->where('testdefgrp.TestSiteID', $id)
->where('testdefgrp.EndDate IS NULL')
->orderBy('testdefgrp.TestGrpID', 'ASC')
->get()->getResultArray();
$row['testdefgrp'] = ValueSet::transformLabels($row['testdefgrp'], [
'TestType' => 'test_type',
]);
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
} elseif ($typeCode === 'TITLE') {
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
} else {
$row['testdeftech'] = $this->db->table('testdeftech')
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
->where('testdeftech.TestSiteID', $id)
->where('testdeftech.EndDate IS NULL')
->get()->getResultArray();
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
if (!empty($row['testdeftech'])) {
$techData = $row['testdeftech'][0];
$refType = $techData['RefType'];
if ($refType === '1') {
$refnumData = $this->modelRefNum
->where('TestSiteID', $id)
->where('EndDate IS NULL')
->orderBy('Display', 'ASC')
->findAll();
$row['refnum'] = array_map(function ($r) {
return [
'RefNumID' => $r['RefNumID'],
'NumRefType' => $r['NumRefType'],
'NumRefTypeVValue' => ValueSet::getLabel('numeric_ref_type', $r['NumRefType']),
'RangeTypeVValue' => ValueSet::getLabel('range_type', $r['RangeType']),
'SexVValue' => ValueSet::getLabel('gender', $r['Sex']),
'LowSignVValue' => ValueSet::getLabel('math_sign', $r['LowSign']),
'HighSignVValue' => ValueSet::getLabel('math_sign', $r['HighSign']),
'High' => $r['High'] !== null ? (int) $r['High'] : null,
'Flag' => $r['Flag']
];
}, $refnumData ?? []);
// $row['numRefTypeOptions'] = ValueSet::getOptions('numeric_ref_type');
$row['rangeTypeOptions'] = ValueSet::getOptions('range_type');
}
if ($refType === '2') {
$reftxtData = $this->modelRefTxt
->where('TestSiteID', $id)
->where('EndDate IS NULL')
->orderBy('RefTxtID', 'ASC')
->findAll();
$row['reftxt'] = array_map(function ($r) {
return [
'RefTxtID' => $r['RefTxtID'],
'TxtRefType' => $r['TxtRefType'],
'TxtRefTypeVValue' => ValueSet::getLabel('text_ref_type', $r['TxtRefType']),
'Sex' => $r['Sex'],
'SexVValue' => ValueSet::getLabel('gender', $r['Sex']),
'AgeStart' => (int) $r['AgeStart'],
'AgeEnd' => (int) $r['AgeEnd'],
'RefTxt' => $r['RefTxt'],
'Flag' => $r['Flag']
];
}, $reftxtData ?? []);
// $row['txtRefTypeOptions'] = ValueSet::getOptions('text_ref_type');
}
}
}
// $row['refTypeOptions'] = ValueSet::getOptions('reference_type');
// $row['sexOptions'] = ValueSet::getOptions('gender');
// $row['mathSignOptions'] = ValueSet::getOptions('math_sign');
return $this->respond(['status' => 'success', 'message' => "Data fetched successfully", 'data' => $row], 200);
}
public function create()
{
$input = $this->request->getJSON(true);
if (!$this->validateData($input, $this->rules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
$this->db->transStart();
try {
$testSiteData = [
'SiteID' => $input['SiteID'],
'TestSiteCode' => $input['TestSiteCode'],
'TestSiteName' => $input['TestSiteName'],
'TestType' => $input['TestType'],
'Description' => $input['Description'] ?? null,
'SeqScr' => $input['SeqScr'] ?? 0,
'SeqRpt' => $input['SeqRpt'] ?? 0,
'IndentLeft' => $input['IndentLeft'] ?? 0,
'FontStyle' => $input['FontStyle'] ?? null,
'VisibleScr' => $input['VisibleScr'] ?? 1,
'VisibleRpt' => $input['VisibleRpt'] ?? 1,
'CountStat' => $input['CountStat'] ?? 1,
'StartDate' => $input['StartDate'] ?? date('Y-m-d H:i:s')
];
$id = $this->model->insert($testSiteData);
if (!$id) {
throw new \Exception("Failed to insert main test definition");
}
$this->handleDetails($id, $input, 'insert');
$this->db->transComplete();
if ($this->db->transStatus() === false) {
return $this->failServerError('Transaction failed');
}
return $this->respondCreated([
'status' => 'created',
'message' => "Test created successfully",
'data' => ['TestSiteId' => $id]
]);
} catch (\Exception $e) {
$this->db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage());
}
}
public function update($id = null)
{
$input = $this->request->getJSON(true);
if (!$id && isset($input["TestSiteID"])) {
$id = $input["TestSiteID"];
}
if (!$id) {
return $this->failValidationErrors('TestSiteID is required.');
}
$existing = $this->model->find($id);
if (!$existing) {
return $this->failNotFound('Test not found');
}
$this->db->transStart();
try {
$testSiteData = [];
$allowedUpdateFields = [
'TestSiteCode',
'TestSiteName',
'TestType',
'Description',
'SeqScr',
'SeqRpt',
'IndentLeft',
'FontStyle',
'VisibleScr',
'VisibleRpt',
'CountStat',
'StartDate'
];
foreach ($allowedUpdateFields as $field) {
if (isset($input[$field])) {
$testSiteData[$field] = $input[$field];
}
}
if (!empty($testSiteData)) {
$this->model->update($id, $testSiteData);
}
$this->handleDetails($id, $input, 'update');
$this->db->transComplete();
if ($this->db->transStatus() === false) {
return $this->failServerError('Transaction failed');
}
return $this->respond([
'status' => 'success',
'message' => "Test updated successfully",
'data' => ['TestSiteId' => $id]
]);
} catch (\Exception $e) {
$this->db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage());
}
}
public function delete($id = null)
{
$input = $this->request->getJSON(true);
if (!$id && isset($input["TestSiteID"])) {
$id = $input["TestSiteID"];
}
if (!$id) {
return $this->failValidationErrors('TestSiteID is required.');
}
$existing = $this->model->find($id);
if (!$existing) {
return $this->failNotFound('Test not found');
}
if (!empty($existing['EndDate'])) {
return $this->failValidationErrors('Test is already disabled');
}
$this->db->transStart();
try {
$now = date('Y-m-d H:i:s');
$this->model->update($id, ['EndDate' => $now]);
$testType = $existing['TestType'];
$typeCode = $testType;
if ($typeCode === 'CALC') {
$this->db->table('testdefcal')
->where('TestSiteID', $id)
->update(['EndDate' => $now]);
} elseif ($typeCode === 'GROUP') {
$this->db->table('testdefgrp')
->where('TestSiteID', $id)
->update(['EndDate' => $now]);
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
$this->db->table('testdeftech')
->where('TestSiteID', $id)
->update(['EndDate' => $now]);
$this->modelRefNum->where('TestSiteID', $id)->set('EndDate', $now)->update();
$this->modelRefTxt->where('TestSiteID', $id)->set('EndDate', $now)->update();
}
$this->db->table('testmap')
->where('TestSiteID', $id)
->update(['EndDate' => $now]);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
return $this->failServerError('Transaction failed');
}
return $this->respond([
'status' => 'success',
'message' => "Test disabled successfully",
'data' => ['TestSiteId' => $id, 'EndDate' => $now]
]);
} catch (\Exception $e) {
$this->db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage());
}
}
private function handleDetails($testSiteID, $input, $action)
{
$testTypeID = $input['TestType'] ?? null;
if (!$testTypeID && $action === 'update') {
$existing = $this->model->find($testSiteID);
$testTypeID = $existing['TestType'] ?? null;
}
if (!$testTypeID)
return;
$typeCode = $testTypeID;
$details = $input['details'] ?? $input;
$details['TestSiteID'] = $testSiteID;
$details['SiteID'] = $input['SiteID'] ?? 1;
switch ($typeCode) {
case 'CALC':
$this->saveCalcDetails($testSiteID, $details, $action);
break;
case 'GROUP':
$this->saveGroupDetails($testSiteID, $details, $input, $action);
break;
case 'TITLE':
if (isset($input['testmap']) && is_array($input['testmap'])) {
$this->saveTestMap($testSiteID, $input['testmap'], $action);
}
break;
case 'TEST':
case 'PARAM':
default:
$this->saveTechDetails($testSiteID, $details, $action, $typeCode);
if (in_array($typeCode, ['TEST', 'PARAM']) && isset($details['RefType'])) {
$refType = $details['RefType'];
if ($refType === '1' && isset($input['refnum']) && is_array($input['refnum'])) {
$this->saveRefNumRanges($testSiteID, $input['refnum'], $action, $input['SiteID'] ?? 1);
}
if ($refType === '2' && isset($input['reftxt']) && is_array($input['reftxt'])) {
$this->saveRefTxtRanges($testSiteID, $input['reftxt'], $action, $input['SiteID'] ?? 1);
}
}
break;
}
if (in_array($typeCode, ['TEST', 'CALC']) && isset($input['testmap']) && is_array($input['testmap'])) {
$this->saveTestMap($testSiteID, $input['testmap'], $action);
}
}
private function saveTechDetails($testSiteID, $data, $action, $typeCode)
{
$techData = [
'TestSiteID' => $testSiteID,
'DisciplineID' => $data['DisciplineID'] ?? null,
'DepartmentID' => $data['DepartmentID'] ?? null,
'ResultType' => $data['ResultType'] ?? null,
'RefType' => $data['RefType'] ?? null,
'VSet' => $data['VSet'] ?? null,
'ReqQty' => $data['ReqQty'] ?? null,
'ReqQtyUnit' => $data['ReqQtyUnit'] ?? null,
'Unit1' => $data['Unit1'] ?? null,
'Factor' => $data['Factor'] ?? null,
'Unit2' => $data['Unit2'] ?? null,
'Decimal' => $data['Decimal'] ?? 2,
'CollReq' => $data['CollReq'] ?? null,
'Method' => $data['Method'] ?? null,
'ExpectedTAT' => $data['ExpectedTAT'] ?? null
];
if ($action === 'update') {
$exists = $this->db->table('testdeftech')
->where('TestSiteID', $testSiteID)
->where('EndDate IS NULL')
->get()->getRowArray();
if ($exists) {
$this->modelTech->update($exists['TestTechID'], $techData);
} else {
$this->modelTech->insert($techData);
}
} else {
$this->modelTech->insert($techData);
}
}
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
{
if ($action === 'update') {
$this->modelRefNum->where('TestSiteID', $testSiteID)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
}
foreach ($ranges as $index => $range) {
$this->modelRefNum->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'NumRefType' => $range['NumRefType'],
'RangeType' => $range['RangeType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'LowSign' => !empty($range['LowSign']) ? $range['LowSign'] : null,
'Low' => !empty($range['Low']) ? (int) $range['Low'] : null,
'HighSign' => !empty($range['HighSign']) ? $range['HighSign'] : null,
'High' => !empty($range['High']) ? (int) $range['High'] : null,
'Flag' => $range['Flag'] ?? null,
'Display' => $index,
'CreateDate' => date('Y-m-d H:i:s')
]);
}
}
private function saveRefTxtRanges($testSiteID, $ranges, $action, $siteID)
{
if ($action === 'update') {
$this->modelRefTxt->where('TestSiteID', $testSiteID)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
}
foreach ($ranges as $range) {
$this->modelRefTxt->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'TxtRefType' => $range['TxtRefType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'RefTxt' => $range['RefTxt'] ?? '',
'Flag' => $range['Flag'] ?? null,
'CreateDate' => date('Y-m-d H:i:s')
]);
}
}
private function saveCalcDetails($testSiteID, $data, $action)
{
$calcData = [
'TestSiteID' => $testSiteID,
'DisciplineID' => $data['DisciplineID'] ?? null,
'DepartmentID' => $data['DepartmentID'] ?? null,
'FormulaInput' => $data['FormulaInput'] ?? null,
'FormulaCode' => $data['FormulaCode'] ?? $data['Formula'] ?? null,
'RefType' => $data['RefType'] ?? 'NMRC',
'Unit1' => $data['Unit1'] ?? $data['ResultUnit'] ?? null,
'Factor' => $data['Factor'] ?? null,
'Unit2' => $data['Unit2'] ?? null,
'Decimal' => $data['Decimal'] ?? 2,
'Method' => $data['Method'] ?? null
];
if ($action === 'update') {
$exists = $this->db->table('testdefcal')
->where('TestSiteID', $testSiteID)
->where('EndDate IS NULL')
->get()->getRowArray();
if ($exists) {
$this->modelCal->update($exists['TestCalID'], $calcData);
} else {
$this->modelCal->insert($calcData);
}
} else {
$this->modelCal->insert($calcData);
}
}
private function saveGroupDetails($testSiteID, $data, $input, $action)
{
if ($action === 'update') {
$this->db->table('testdefgrp')
->where('TestSiteID', $testSiteID)
->update(['EndDate' => date('Y-m-d H:i:s')]);
}
$members = $data['members'] ?? ($input['Members'] ?? []);
if (is_array($members)) {
foreach ($members as $m) {
$memberID = is_array($m) ? ($m['Member'] ?? ($m['TestSiteID'] ?? null)) : $m;
if ($memberID) {
$this->modelGrp->insert([
'TestSiteID' => $testSiteID,
'Member' => $memberID
]);
}
}
}
}
private function saveTestMap($testSiteID, $mappings, $action)
{
if ($action === 'update') {
$this->db->table('testmap')
->where('TestSiteID', $testSiteID)
->update(['EndDate' => date('Y-m-d H:i:s')]);
}
if (is_array($mappings)) {
foreach ($mappings as $map) {
$mapData = [
'TestSiteID' => $testSiteID,
'HostType' => $map['HostType'] ?? null,
'HostID' => $map['HostID'] ?? null,
'HostDataSource' => $map['HostDataSource'] ?? null,
'HostTestCode' => $map['HostTestCode'] ?? null,
'HostTestName' => $map['HostTestName'] ?? null,
'ClientType' => $map['ClientType'] ?? null,
'ClientID' => $map['ClientID'] ?? null,
'ClientDataSource' => $map['ClientDataSource'] ?? null,
'ConDefID' => $map['ConDefID'] ?? null,
'ClientTestCode' => $map['ClientTestCode'] ?? null,
'ClientTestName' => $map['ClientTestName'] ?? null
];
$this->modelMap->insert($mapData);
}
}
}
}