2026-04-17 05:38:11 +07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Controllers\User;
|
|
|
|
|
|
|
|
|
|
use App\Controllers\BaseController;
|
|
|
|
|
use App\Models\User\UserModel;
|
|
|
|
|
use App\Traits\PatchValidationTrait;
|
|
|
|
|
use App\Traits\ResponseTrait;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User Management Controller
|
|
|
|
|
* Handles CRUD operations for users
|
|
|
|
|
*/
|
|
|
|
|
class UserController extends BaseController
|
|
|
|
|
{
|
|
|
|
|
use ResponseTrait;
|
|
|
|
|
use PatchValidationTrait;
|
|
|
|
|
|
|
|
|
|
protected $model;
|
|
|
|
|
protected $db;
|
|
|
|
|
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
$this->db = \Config\Database::connect();
|
|
|
|
|
$this->model = new UserModel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* List users with pagination and search
|
|
|
|
|
* GET /api/user?page=1&per_page=20&search=term
|
|
|
|
|
*/
|
|
|
|
|
public function index()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$page = (int)($this->request->getGet('page') ?? 1);
|
|
|
|
|
$perPage = (int)($this->request->getGet('per_page') ?? 20);
|
|
|
|
|
$search = $this->request->getGet('search');
|
|
|
|
|
|
|
|
|
|
// Build query
|
|
|
|
|
$builder = $this->model->where('DelDate', null);
|
|
|
|
|
|
|
|
|
|
// Apply search if provided
|
|
|
|
|
if ($search) {
|
|
|
|
|
$builder->groupStart()
|
|
|
|
|
->like('Username', $search)
|
|
|
|
|
->orLike('Email', $search)
|
|
|
|
|
->orLike('Name', $search)
|
|
|
|
|
->groupEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get total count for pagination
|
|
|
|
|
$total = $builder->countAllResults(false);
|
|
|
|
|
|
|
|
|
|
// Get paginated results
|
|
|
|
|
$users = $builder
|
|
|
|
|
->orderBy('UserID', 'DESC')
|
|
|
|
|
->limit($perPage, ($page - 1) * $perPage)
|
|
|
|
|
->findAll();
|
|
|
|
|
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'success',
|
|
|
|
|
'message' => 'Users retrieved successfully',
|
|
|
|
|
'data' => [
|
|
|
|
|
'users' => $users,
|
|
|
|
|
'pagination' => [
|
|
|
|
|
'current_page' => $page,
|
|
|
|
|
'per_page' => $perPage,
|
|
|
|
|
'total' => $total,
|
|
|
|
|
'total_pages' => ceil($total / $perPage)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
], 200);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
log_message('error', 'UserController::index error: ' . $e->getMessage());
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to retrieve users',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get single user by ID
|
|
|
|
|
* GET /api/user/(:num)
|
|
|
|
|
*/
|
|
|
|
|
public function show($id)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$user = $this->model->where('UserID', $id)
|
|
|
|
|
->where('DelDate', null)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (empty($user)) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'User not found',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'success',
|
|
|
|
|
'message' => 'User retrieved successfully',
|
|
|
|
|
'data' => $user
|
|
|
|
|
], 200);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
log_message('error', 'UserController::show error: ' . $e->getMessage());
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to retrieve user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create new user
|
|
|
|
|
* POST /api/user
|
|
|
|
|
*/
|
|
|
|
|
public function create()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$data = $this->request->getJSON(true);
|
|
|
|
|
|
|
|
|
|
// Validation rules
|
|
|
|
|
$rules = [
|
|
|
|
|
'Username' => 'required|min_length[3]|max_length[50]|is_unique[users.Username]',
|
|
|
|
|
'Email' => 'required|valid_email|is_unique[users.Email]',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (!$this->validateData($data, $rules)) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Validation failed',
|
|
|
|
|
'data' => $this->validator->getErrors()
|
|
|
|
|
], 400);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set default values
|
|
|
|
|
$data['IsActive'] = $data['IsActive'] ?? true;
|
|
|
|
|
$data['CreatedAt'] = date('Y-m-d H:i:s');
|
|
|
|
|
|
|
|
|
|
$userId = $this->model->insert($data);
|
|
|
|
|
|
|
|
|
|
if (!$userId) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to create user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'success',
|
|
|
|
|
'message' => 'User created successfully',
|
|
|
|
|
'data' => [
|
|
|
|
|
'UserID' => $userId,
|
|
|
|
|
'Username' => $data['Username'],
|
|
|
|
|
'Email' => $data['Email']
|
|
|
|
|
]
|
|
|
|
|
], 201);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
log_message('error', 'UserController::create error: ' . $e->getMessage());
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to create user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update existing user
|
|
|
|
|
* PATCH /api/user/(:num)
|
|
|
|
|
*/
|
|
|
|
|
public function update($id)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$data = $this->requirePatchPayload($this->request->getJSON(true));
|
|
|
|
|
if ($data === null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($id) || !ctype_digit((string) $id)) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'UserID is required',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 400);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isset($data['UserID']) && (string) $data['UserID'] !== (string) $id) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'UserID in URL does not match body',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 400);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$userId = (int) $id;
|
|
|
|
|
|
|
|
|
|
// Check if user exists
|
|
|
|
|
$user = $this->model->where('UserID', $userId)
|
|
|
|
|
->where('DelDate', null)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (empty($user)) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'User not found',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove UserID from data array
|
|
|
|
|
unset($data['UserID']);
|
|
|
|
|
|
|
|
|
|
// Don't allow updating these fields
|
|
|
|
|
unset($data['CreatedAt']);
|
|
|
|
|
unset($data['Username']); // Username should not change
|
|
|
|
|
|
|
|
|
|
$data['UpdatedAt'] = date('Y-m-d H:i:s');
|
|
|
|
|
|
|
|
|
|
$updated = $this->model->update($userId, $data);
|
|
|
|
|
|
|
|
|
|
if (!$updated) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to update user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'success',
|
|
|
|
|
'message' => 'User updated successfully',
|
|
|
|
|
'data' => [
|
|
|
|
|
'UserID' => $userId,
|
|
|
|
|
'updated_fields' => array_keys($data)
|
|
|
|
|
]
|
|
|
|
|
], 200);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
log_message('error', 'UserController::update error: ' . $e->getMessage());
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to update user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete user (soft delete)
|
|
|
|
|
* DELETE /api/user/(:num)
|
|
|
|
|
*/
|
|
|
|
|
public function delete($id)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
// Check if user exists
|
|
|
|
|
$user = $this->model->where('UserID', $id)
|
|
|
|
|
->where('DelDate', null)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (empty($user)) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'User not found',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Soft delete by setting DelDate
|
|
|
|
|
$deleted = $this->model->update($id, [
|
|
|
|
|
'DelDate' => date('Y-m-d H:i:s'),
|
|
|
|
|
'IsActive' => false
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (!$deleted) {
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to delete user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'success',
|
|
|
|
|
'message' => 'User deleted successfully',
|
|
|
|
|
'data' => ['UserID' => $id]
|
|
|
|
|
], 200);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
log_message('error', 'UserController::delete error: ' . $e->getMessage());
|
|
|
|
|
return $this->respond([
|
|
|
|
|
'status' => 'failed',
|
|
|
|
|
'message' => 'Failed to delete user',
|
|
|
|
|
'data' => null
|
|
|
|
|
], 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|