# AGENTS.md This file provides guidance to agents when working with code in this repository. ## Project Overview This is a CodeIgniter 4 PHP application for a laboratory management system (CMOD). It uses SQL Server database with role-based access control for different user types (admin, doctor/analyst, customer service). ## Commands ```bash # Run all tests ./vendor/bin/phpunit composer test # Run single test file ./vendor/bin/phpunit tests/unit/HealthTest.php # Run single test method ./vendor/bin/phpunit tests/unit/HealthTest.php --filter testIsDefinedAppPath # Development server (Linux/Mac) php spark serve # List all routes php spark list # Create controller php spark make:controller Admin # Create model php spark make:model User ``` ## Code Style Guidelines ### PHP Standards - Use PHP 8.1+ features (typed properties, match expressions where appropriate) - Always declare return types for public methods - Use `strict_types=1` not required (CodeIgniter doesn't use it) - No comments unless explaining complex logic (per project convention) ### Naming Conventions - **Classes**: PascalCase (e.g., `Admin`, `UserController`) - **Methods**: camelCase (e.g., `index()`, `getUsers()`) - **Variables**: camelCase (e.g., `$userId`, `$dataList`) - **Constants**: UPPER_SNAKE_CASE (e.g., `DB_HOST`) - **Database tables**: UPPER_SNAKE_CASE (e.g., `GDC_CMOD.dbo.USERS`) - **Views**: lowercase with underscores (e.g., `admin/index.php`) ### Controller Patterns #### Base Controllers - All controllers extend `App\Controllers\BaseController` - BaseController extends CodeIgniter\Controller ```php namespace App\Controllers; class Admin extends BaseController { public function index() { // Method body } } ``` #### API Controllers - Controllers use `ResponseTrait` for API responses - Use `$this->respond()` or `$this->response->setJSON()` for responses ```php namespace App\Controllers; use App\Controllers\BaseController; use CodeIgniter\API\ResponseTrait; class Users extends BaseController { use ResponseTrait; protected $db; public function __construct() { $this->db = \Config\Database::connect(); helper(['url', 'form', 'text']); } public function index() { $query = $this->db->query("SELECT * FROM table"); return $this->respond(['data' => $query->getResultArray()]); } } ``` ### Database Operations #### Connection Pattern ```php $this->db = \Config\Database::connect(); ``` #### Query Methods - `getRowArray()` - returns single row as associative array - `getResultArray()` - returns multiple rows as array of arrays - Use parameterized queries to prevent SQL injection ```php $query = $this->db->query("SELECT * FROM table WHERE id = ?", [$id]); $row = $query->getRowArray(); $results = $query->getResultArray(); ``` #### Transactions ```php $this->db->transBegin(); try { $this->db->query("INSERT INTO ...", [$data]); $this->db->transCommit(); } catch (\Throwable $e) { $this->db->transRollback(); return $this->response->setJSON(['message' => 'Error']); } ``` ### Session Management #### Session Structure ```php $session->set([ 'isLoggedIn' => true, 'userid' => (string) $user['USERID'], 'userlevel' => (int) $user['USERLEVEL'], 'userrole' => (string) $role, // 'admin', 'doctor', 'analyst', 'cs' ]); ``` #### Session Values - `isLoggedIn`: bool - `userid`: string - `userlevel`: int - `userrole`: string ### Role-Based Access Control #### Role Values - `1` = admin - `2` = doctor (or lab/analyst) - `3` = analyst - `4` = cs (customer service) #### Route Filter Syntax ```php // Single role ['filter' => 'role:1'] // Multiple roles ['filter' => 'role:1,2'] ``` ### Request/Response Patterns #### Getting Input ```php // POST data $input = $this->request->getJSON(true); $userid = $input['userid']; // Query parameters $date1 = $this->request->getVar('date1') ?? date('Y-m-d'); ``` #### JSON Response (V2 API) ```php return $this->respond(['data' => $results]); return $this->response->setJSON(['message' => 'Success']); ``` #### View Response (Traditional) ```php return view('admin/index', $data); ``` #### Redirect with Errors ```php return redirect()->back()->with('errors', ['key' => 'message']); ``` ### API Endpoint Patterns #### Validation Endpoints - `POST /api/{resource}/validate/{id}` - validate a record - `DELETE /api/{resource}/validate/{id}` - unvalidate a record #### Route Examples ```php // Admin routes $routes->group('admin', ['filter' => 'role:1'], function($routes) { $routes->get('/', 'Admin::index'); $routes->get('users', 'Admin::users'); $routes->get('api/users', 'Users::index'); $routes->post('api/users', 'Users::create'); }); // Lab routes $routes->group('lab', ['filter' => 'role:2'], function($routes) { $routes->get('/', 'Lab::index'); $routes->get('api/requests', 'Requests::index'); }); ``` ### Error Handling #### Database Operations ```php try { // DB operations } catch (\Throwable $e) { // Handle error return $this->response->setJSON(['message' => 'Server error']); } ``` #### Validation Errors ```php if ($condition) { return $this->response->setJSON(['message' => 'Error message']); } ``` ### Views #### View Pattern - Views are plain PHP files in `app/Views/` - Use `` syntax - Pass data as associative array ```php // Controller $data['dataList'] = $results; return view('admin/index', $data); // View