Kotchasan Framework Documentation
Controller Classes - คลาสควบคุม
Controller Classes - คลาสควบคุม
ภาพรวม
Controller Classes ใน Kotchasan Framework เป็นส่วนประกอบหลักของ MVC pattern ที่ทำหน้าที่เป็นตัวกลางระหว่าง Model และ View โดยจัดการ HTTP requests, business logic, และการส่งผ่านข้อมูลไปยัง View
คุณสมบัติหลัก
- MVC Pattern: ใช้งานตาม Model-View-Controller pattern
- Request Handling: จัดการ HTTP requests ทุกประเภท
- API Support: รองรับการสร้าง REST API
- Authentication: ระบบยืนยันตัวตนและการอนุญาต
- Validation: ตรวจสอบความถูกต้องของข้อมูล
- Error Handling: จัดการข้อผิดพลาดอย่างสม่ำเสมอ
- Response Formatting: จัดรูปแบบการตอบกลับ
สารบัญ
- Controller Base Class
- ApiController - REST API Controller
- HTTP Request และ Response Handling
- Authentication และ Security
- Error Handling และ Validation
- Best Practices - แนวทางปฏิบัติที่ดี
Controller Base Class
Controller base class เป็นคลาสพื้นฐานสำหรับการสร้าง controllers ทั้งหมด
การใช้งาน Controller พื้นฐาน
use Kotchasan\Database;
use Kotchasan\Controller;
use Kotchasan\Http\Request;
class UserController extends Controller
{
/
แสดงรายการผู้ใช้
/
public function index(Request $request)
{
// ดึงข้อมูลผู้ใช้
$users = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status'])
->from('users')
->where(['status', 'active'])
->orderBy('name')
->fetchAll();
// ส่งข้อมูลไปยัง View
return View::create()
->assign('users', $users)
->render('user/index');
}
/
แสดงฟอร์มสร้างผู้ใช้ใหม่
/
public function create(Request $request)
{
return View::create()->render('user/create');
}
/
บันทึกผู้ใช้ใหม่
/
public function store(Request $request)
{
$input = $request->getParsedBody();
// Validation
$errors = $this->validateUserInput($input);
if (!empty($errors)) {
return View::create()
->assign('errors', $errors)
->assign('input', $input)
->render('user/create');
}
// บันทึกข้อมูล
$userId = Kotchasan\Database::create()
->insert('users')
->values([
'name' => $input['name'],
'email' => $input['email'],
'password' => password_hash($input['password'], PASSWORD_DEFAULT),
'created_at' => date('Y-m-d H:i:s')
])
->execute();
// Redirect หลังจากบันทึกสำเร็จ
return Response::create()
->withStatus(302)
->withHeader('Location', '/users/' . $userId);
}
/
แสดงข้อมูลผู้ใช้
/
public function show(Request $request)
{
$userId = $request->getAttribute('id');
$user = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'created_at'])
->from('users')
->where(['id', $userId])
->first();
if (!$user) {
return Response::create()
->withStatus(404)
->getBody()->write('User not found');
}
return View::create()
->assign('user', $user)
->render('user/show');
}
/
Validation สำหรับข้อมูลผู้ใช้
/
private function validateUserInput($input)
{
$errors = [];
if (empty($input['name'])) {
$errors['name'] = 'ชื่อเป็นข้อมูลที่จำเป็น';
}
if (empty($input['email'])) {
$errors['email'] = 'อีเมลเป็นข้อมูลที่จำเป็น';
} elseif (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'รูปแบบอีเมลไม่ถูกต้อง';
}
if (empty($input['password'])) {
$errors['password'] = 'รหัสผ่านเป็นข้อมูลที่จำเป็น';
} elseif (strlen($input['password']) < 6) {
$errors['password'] = 'รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร';
}
return $errors;
}
}Factory Pattern
// การสร้าง Controller instance
$controller = Controller::create();
// การใช้งานใน routing
$userController = UserController::create();
$response = $userController->index($request);ApiController - REST API Controller
ApiController เป็นคลาสพิเศษสำหรับการสร้าง REST API endpoints
คุณสมบัติของ ApiController
- REST API Support: รองรับ REST API patterns
- JSON Response: ส่งผลลัพธ์เป็น JSON
- Authentication: ระบบยืนยันตัวตนด้วย Token
- CORS Support: รองรับ Cross-Origin Resource Sharing
- Rate Limiting: จำกัดอัตราการเรียกใช้ API
- Error Standardization: มาตรฐานการส่งข้อผิดพลาด
การใช้งาน ApiController
use Kotchasan\Database;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
use Kotchasan\Http\Response;
class UserApiController extends ApiController
{
/
ดึงรายการผู้ใช้ - GET /api/users
/
public function index(Request $request): Response
{
try {
// ตรวจสอบ authentication
$this->requireAuthentication($request);
// ดึงพารามิเตอร์จาก query string
$page = (int) $request->getQueryParam('page', 1);
$limit = (int) $request->getQueryParam('limit', 20);
$search = $request->getQueryParam('search', '');
// สร้าง query
$query = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status', 'created_at'])
->from('users');
// เพิ่มเงื่อนไขการค้นหา
if (!empty($search)) {
$query->where(function($q) use ($search) {
$q->where(['name', 'LIKE', "%{$search}%"])
->orWhere(['email', 'LIKE', "%{$search}%"]);
});
}
// นับจำนวนทั้งหมด
$total = $query->count();
// ดึงข้อมูลพร้อม pagination
$users = $query
->orderBy('created_at', 'DESC')
->limit($limit, ($page - 1) $limit)
->fetchAll();
// ส่งผลลัพธ์แบบ paginated
return $this->paginatedResponse($users, $total, $page, $limit);
} catch (Exception $e) {
return $this->errorResponse(
'เกิดข้อผิดพลาดในการดึงข้อมูลผู้ใช้',
500,
['error' => $e->getMessage()]
);
}
}
/
ดึงข้อมูลผู้ใช้เฉพาะ - GET /api/users/{id}
/
public function show(Request $request): Response
{
try {
$this->requireAuthentication($request);
$userId = $request->getAttribute('id');
$user = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status', 'created_at', 'updated_at'])
->from('users')
->where(['id', $userId])
->first();
if (!$user) {
return $this->errorResponse('ไม่พบข้อมูลผู้ใช้', 404);
}
return $this->successResponse($user, 'ดึงข้อมูลผู้ใช้สำเร็จ');
} catch (Exception $e) {
return $this->errorResponse(
'เกิดข้อผิดพลาดในการดึงข้อมูลผู้ใช้',
500,
['error' => $e->getMessage()]
);
}
}
/
สร้างผู้ใช้ใหม่ - POST /api/users
/
public function store(Request $request): Response
{
try {
$this->requireAuthentication($request);
$input = $request->getParsedBody();
// Validation
$validationErrors = $this->validateInput([
'name' => 'required|string|min:2|max:100',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:6'
], $input);
if (!empty($validationErrors)) {
return $this->errorResponse(
'ข้อมูลไม่ถูกต้อง',
422,
$validationErrors
);
}
// สร้างผู้ใช้ใหม่
$userId = Kotchasan\Database::create()
->insert('users')
->values([
'name' => $input['name'],
'email' => $input['email'],
'password' => password_hash($input['password'], PASSWORD_DEFAULT),
'status' => 'active',
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
])
->execute();
// ดึงข้อมูลผู้ใช้ที่สร้างใหม่
$newUser = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status', 'created_at'])
->from('users')
->where(['id', $userId])
->first();
return $this->successResponse(
$newUser,
'สร้างผู้ใช้ใหม่สำเร็จ',
201
);
} catch (Exception $e) {
return $this->errorResponse(
'เกิดข้อผิดพลาดในการสร้างผู้ใช้',
500,
['error' => $e->getMessage()]
);
}
}
/
อัปเดตข้อมูลผู้ใช้ - PUT/PATCH /api/users/{id}
/
public function update(Request $request): Response
{
try {
$this->requireAuthentication($request);
$userId = $request->getAttribute('id');
$input = $request->getParsedBody();
// ตรวจสอบว่าผู้ใช้มีอยู่จริง
$existingUser = Kotchasan\Database::create()
->select(['id'])
->from('users')
->where(['id', $userId])
->first();
if (!$existingUser) {
return $this->errorResponse('ไม่พบข้อมูลผู้ใช้', 404);
}
// Validation
$validationErrors = $this->validateInput([
'name' => 'string|min:2|max:100',
'email' => "email|unique:users,email,{$userId}",
'password' => 'string|min:6'
], $input);
if (!empty($validationErrors)) {
return $this->errorResponse(
'ข้อมูลไม่ถูกต้อง',
422,
$validationErrors
);
}
// เตรียมข้อมูลสำหรับอัปเดต
$updateData = ['updated_at' => date('Y-m-d H:i:s')];
if (isset($input['name'])) {
$updateData['name'] = $input['name'];
}
if (isset($input['email'])) {
$updateData['email'] = $input['email'];
}
if (isset($input['password'])) {
$updateData['password'] = password_hash($input['password'], PASSWORD_DEFAULT);
}
// อัปเดตข้อมูล
Kotchasan\Database::create()
->update('users')
->set($updateData)
->where(['id', $userId])
->execute();
// ดึงข้อมูลที่อัปเดตแล้ว
$updatedUser = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status', 'updated_at'])
->from('users')
->where(['id', $userId])
->first();
return $this->successResponse(
$updatedUser,
'อัปเดตข้อมูลผู้ใช้สำเร็จ'
);
} catch (Exception $e) {
return $this->errorResponse(
'เกิดข้อผิดพลาดในการอัปเดตข้อมูลผู้ใช้',
500,
['error' => $e->getMessage()]
);
}
}
/
ลบผู้ใช้ - DELETE /api/users/{id}
*/
public function destroy(Request $request): Response
{
try {
$this->requireAuthentication($request);
$userId = $request->getAttribute('id');
// ตรวจสอบว่าผู้ใช้มีอยู่จริง
$existingUser = Kotchasan\Database::create()
->select(['id', 'name'])
->from('users')
->where(['id', $userId])
->first();
if (!$existingUser) {
return $this->errorResponse('ไม่พบข้อมูลผู้ใช้', 404);
}
// ลบข้อมูลผู้ใช้
Kotchasan\Database::create()
->delete('users')
->where(['id', $userId])
->execute();
return $this->successResponse(
['deleted_user' => $existingUser],
'ลบผู้ใช้สำเร็จ'
);
} catch (Exception $e) {
return $this->errorResponse(
'เกิดข้อผิดพลาดในการลบผู้ใช้',
500,
['error' => $e->getMessage()]
);
}
}
}HTTP Request และ Response Handling
Request Handling
use Kotchasan\Database;
class ProductController extends Controller
{
public function search(Request $request)
{
// ดึงข้อมูลจาก Query Parameters
$query = $request->getQueryParam('q', '');
$category = $request->getQueryParam('category', '');
$minPrice = (float) $request->getQueryParam('min_price', 0);
$maxPrice = (float) $request->getQueryParam('max_price', 0);
$page = (int) $request->getQueryParam('page', 1);
$limit = (int) $request->getQueryParam('limit', 20);
// ดึงข้อมูลจาก Request Body (POST/PUT)
$postData = $request->getParsedBody();
// ดึงข้อมูลจาก Headers
$authToken = $request->getHeaderLine('Authorization');
$contentType = $request->getHeaderLine('Content-Type');
// ดึงข้อมูลจาก Cookies
$sessionId = $request->getCookieParam('session_id');
// ดึงข้อมูลจาก Route Parameters
$productId = $request->getAttribute('id');
// ดึงข้อมูลไฟล์ที่อัปโหลด
$uploadedFiles = $request->getUploadedFiles();
// สร้าง query สำหรับค้นหา
$searchQuery = Kotchasan\Database::create()
->select(['id', 'name', 'price', 'category', 'image'])
->from('products');
// เพิ่มเงื่อนไขการค้นหา
if (!empty($query)) {
$searchQuery->where(['name', 'LIKE', "%{$query}%"]);
}
if (!empty($category)) {
$searchQuery->where(['category', $category]);
}
if ($minPrice > 0) {
$searchQuery->where(['price', '>=', $minPrice]);
}
if ($maxPrice > 0) {
$searchQuery->where(['price', '<=', $maxPrice]);
}
// นับจำนวนผลลัพธ์
$total = $searchQuery->count();
// ดึงข้อมูลพร้อม pagination
$products = $searchQuery
->orderBy('name')
->limit($limit, ($page - 1) * $limit)
->fetchAll();
return View::create()
->assign('products', $products)
->assign('total', $total)
->assign('currentPage', $page)
->assign('totalPages', ceil($total / $limit))
->render('product/search');
}
}Response Handling
class ResponseController extends Controller
{
/
ส่ง JSON Response
/
public function jsonResponse()
{
$data = [
'status' => 'success',
'message' => 'ดึงข้อมูลสำเร็จ',
'data' => [
'users' => [
['id' => 1, 'name' => 'John'],
['id' => 2, 'name' => 'Jane']
]
],
'timestamp' => time()
];
return Response::create()
->withHeader('Content-Type', 'application/json')
->withStatus(200)
->getBody()->write(json_encode($data));
}
/
ส่ง HTML Response
/
public function htmlResponse()
{
$content = View::create()
->assign('title', 'หน้าแรก')
->assign('message', 'ยินดีต้อนรับ')
->render('home/index');
return Response::create()
->withHeader('Content-Type', 'text/html; charset=utf-8')
->withStatus(200)
->getBody()->write($content);
}
/
Redirect Response
/
public function redirectResponse()
{
return Response::create()
->withStatus(302)
->withHeader('Location', '/dashboard');
}
/
File Download Response
/
public function downloadFile(Request $request)
{
$filename = $request->getAttribute('filename');
$filePath = '/path/to/files/' . $filename;
if (!file_exists($filePath)) {
return Response::create()
->withStatus(404)
->getBody()->write('File not found');
}
$fileContent = file_get_contents($filePath);
return Response::create()
->withHeader('Content-Type', 'application/octet-stream')
->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
->withHeader('Content-Length', strlen($fileContent))
->withStatus(200)
->getBody()->write($fileContent);
}
/
Image Response
/
public function serveImage(Request $request)
{
$imageId = $request->getAttribute('id');
$imagePath = '/path/to/images/' . $imageId . '.jpg';
if (!file_exists($imagePath)) {
return Response::create()->withStatus(404);
}
$imageContent = file_get_contents($imagePath);
return Response::create()
->withHeader('Content-Type', 'image/jpeg')
->withHeader('Cache-Control', 'public, max-age=86400')
->withStatus(200)
->getBody()->write($imageContent);
}
}Authentication และ Security
Token-based Authentication
use Kotchasan\Database;
class AuthController extends Controller
{
/
Login และสร้าง Token
/
public function login(Request $request): Response
{
$input = $request->getParsedBody();
// Validation
if (empty($input['email']) || empty($input['password'])) {
return $this->errorResponse('กรุณากรอกอีเมลและรหัสผ่าน', 400);
}
// ตรวจสอบผู้ใช้
$user = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'password', 'status'])
->from('users')
->where(['email', $input['email']])
->first();
if (!$user || !password_verify($input['password'], $user['password'])) {
return $this->errorResponse('อีเมลหรือรหัสผ่านไม่ถูกต้อง', 401);
}
if ($user['status'] !== 'active') {
return $this->errorResponse('บัญชีผู้ใช้ถูกปิดใช้งาน', 403);
}
// สร้าง JWT Token
$payload = [
'user_id' => $user['id'],
'email' => $user['email'],
'iat' => time(),
'exp' => time() + (24 60 60) // 24 ชั่วโมง
];
$token = $this->generateJWTToken($payload);
// อัปเดต last login
Kotchasan\Database::create()
->update('users')
->set(['last_login' => date('Y-m-d H:i:s')])
->where(['id', $user['id']])
->execute();
return $this->successResponse([
'user' => [
'id' => $user['id'],
'name' => $user['name'],
'email' => $user['email']
],
'token' => $token,
'expires_in' => 86400
], 'เข้าสู่ระบบสำเร็จ');
}
/
ตรวจสอบ Token
/
protected function requireAuthentication(Request $request)
{
$authHeader = $request->getHeaderLine('Authorization');
if (empty($authHeader)) {
throw new AuthenticationException('Missing Authorization header', 401);
}
// ดึง Token จาก Authorization header
if (!preg_match('/Bearer\s+(.)$/i', $authHeader, $matches)) {
throw new AuthenticationException('Invalid Authorization header format', 401);
}
$token = $matches[1];
// ตรวจสอบ JWT Token
try {
$payload = $this->verifyJWTToken($token);
// ตรวจสอบว่า token ยังไม่หมดอายุ
if ($payload['exp'] < time()) {
throw new AuthenticationException('Token expired', 401);
}
// ดึงข้อมูลผู้ใช้
$user = Kotchasan\Database::create()
->select(['id', 'name', 'email', 'status'])
->from('users')
->where(['id', $payload['user_id']])
->first();
if (!$user || $user['status'] !== 'active') {
throw new AuthenticationException('Invalid user', 401);
}
// เก็บข้อมูลผู้ใช้ใน request attribute
$request = $request->withAttribute('user', $user);
return $user;
} catch (Exception $e) {
throw new AuthenticationException('Invalid token: ' . $e->getMessage(), 401);
}
}
/
Logout
/
public function logout(Request $request): Response
{
// ใน JWT token-based auth, logout ทำได้โดยการลบ token ที่ client
// หรือเก็บ blacklist ของ token ที่ logout แล้ว
return $this->successResponse(
['message' => 'Logged out successfully'],
'ออกจากระบบสำเร็จ'
);
}
/
ดึงข้อมูล profile ของผู้ใช้ปัจจุบัน
*/
public function profile(Request $request): Response
{
$user = $this->requireAuthentication($request);
return $this->successResponse($user, 'ดึงข้อมูล profile สำเร็จ');
}
}Error Handling และ Validation
Centralized Error Handling
class ErrorController extends Controller
{
/
จัดการ 404 Error
/
public function notFound(Request $request): Response
{
$isApiRequest = strpos($request->getHeaderLine('Content-Type'), 'application/json') !== false
|| strpos($request->getUri()->getPath(), '/api/') === 0;
if ($isApiRequest) {
return $this->errorResponse('Endpoint not found', 404);
}
return View::create()
->assign('title', 'ไม่พบหน้าที่ต้องการ')
->assign('message', 'ขออภัย ไม่พบหน้าที่คุณต้องการ')
->render('errors/404')
->withStatus(404);
}
/
จัดการ 500 Error
/
public function serverError(Request $request, Exception $exception): Response
{
// Log error
error_log("Server Error: " . $exception->getMessage() . "\n" . $exception->getTraceAsString());
$isApiRequest = strpos($request->getHeaderLine('Content-Type'), 'application/json') !== false
|| strpos($request->getUri()->getPath(), '/api/') === 0;
if ($isApiRequest) {
$errorData = [
'error' => 'Internal server error'
];
// แสดงรายละเอียด error ใน development mode
if (self::$cfg->debug) {
$errorData['debug'] = [
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace()
];
}
return $this->errorResponse(
'เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์',
500,
$errorData
);
}
return View::create()
->assign('title', 'เกิดข้อผิดพลาด')
->assign('message', 'เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์')
->assign('debug', self::$cfg->debug ? $exception : null)
->render('errors/500')
->withStatus(500);
}
}Input Validation
use Kotchasan\Database;
class ValidationController extends Controller
{
/
Validation Rules
/
protected function getValidationRules()
{
return [
'user_create' => [
'name' => 'required|string|min:2|max:100',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:6|confirmed',
'phone' => 'nullable|string|regex:/^[0-9\-\+\s\(\)]+$/',
'age' => 'nullable|integer|min:18|max:100'
],
'user_update' => [
'name' => 'string|min:2|max:100',
'email' => 'email|unique:users,email,{id}',
'password' => 'string|min:6|confirmed',
'phone' => 'nullable|string|regex:/^[0-9\-\+\s\(\)]+$/',
'age' => 'nullable|integer|min:18|max:100'
],
'product_create' => [
'name' => 'required|string|min:2|max:200',
'price' => 'required|numeric|min:0',
'category_id' => 'required|integer|exists:categories,id',
'description' => 'nullable|string|max:1000',
'image' => 'nullable|file|mimes:jpg,jpeg,png|max:2048'
]
];
}
/
ตรวจสอบ Input ตาม Rules
/
protected function validateInput(string $ruleSet, array $input, array $context = []): array
{
$rules = $this->getValidationRules()[$ruleSet] ?? [];
$errors = [];
foreach ($rules as $field => $rule) {
$ruleList = explode('|', $rule);
$value = $input[$field] ?? null;
foreach ($ruleList as $singleRule) {
$error = $this->validateField($field, $value, $singleRule, $input, $context);
if ($error) {
$errors[$field] = $error;
break; // หยุดตรวจสอบ rule อื่นสำหรับ field นี้
}
}
}
return $errors;
}
/
ตรวจสอบ Field เดียว
/
private function validateField(string $field, $value, string $rule, array $input, array $context): ?string
{
$ruleParts = explode(':', $rule, 2);
$ruleName = $ruleParts[0];
$ruleParam = $ruleParts[1] ?? null;
switch ($ruleName) {
case 'required':
if (empty($value)) {
return "ฟิลด์ {$field} เป็นข้อมูลที่จำเป็น";
}
break;
case 'string':
if (!is_string($value)) {
return "ฟิลด์ {$field} ต้องเป็นข้อความ";
}
break;
case 'integer':
if (!is_numeric($value) || !is_int((int)$value)) {
return "ฟิลด์ {$field} ต้องเป็นจำนวนเต็ม";
}
break;
case 'numeric':
if (!is_numeric($value)) {
return "ฟิลด์ {$field} ต้องเป็นตัวเลข";
}
break;
case 'email':
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
return "ฟิลด์ {$field} ต้องเป็นอีเมลที่ถูกต้อง";
}
break;
case 'min':
$min = (int)$ruleParam;
if (strlen($value) < $min) {
return "ฟิลด์ {$field} ต้องมีอย่างน้อย {$min} ตัวอักษร";
}
break;
case 'max':
$max = (int)$ruleParam;
if (strlen($value) > $max) {
return "ฟิลด์ {$field} ต้องมีไม่เกิน {$max} ตัวอักษร";
}
break;
case 'unique':
list($table, $column, $except) = explode(',', $ruleParam . ',,');
$except = str_replace('{id}', $context['id'] ?? '', $except);
$query = Kotchasan\Database::create()
->select(['id'])
->from($table)
->where([$column, $value]);
if (!empty($except)) {
$query->where(['id', '!=', $except]);
}
if ($query->first()) {
return "ฟิลด์ {$field} มีการใช้งานแล้ว";
}
break;
case 'exists':
list($table, $column) = explode(',', $ruleParam);
$exists = Kotchasan\Database::create()
->select(['id'])
->from($table)
->where([$column, $value])
->first();
if (!$exists) {
return "ฟิลด์ {$field} ไม่พบข้อมูลที่เกี่ยวข้อง";
}
break;
case 'confirmed':
$confirmField = $field . '_confirmation';
if ($value !== ($input[$confirmField] ?? null)) {
return "ฟิลด์ {$field} ไม่ตรงกับการยืนยัน";
}
break;
}
return null;
}
}Best Practices - แนวทางปฏิบัติที่ดี
1. Controller Organization
// จัดระเบียบ Controllers ตาม feature
// app/Controllers/User/UserController.php
// app/Controllers/Product/ProductController.php
// app/Controllers/Order/OrderController.php
namespace App\Controllers\User;
class UserController extends Controller
{
// เก็บ logic ที่เกี่ยวข้องกับ User เท่านั้น
public function index() { / ... / }
public function show() { / ... / }
public function create() { / ... / }
public function update() { / ... / }
public function delete() { / ... / }
}2. Dependency Injection
class UserController extends Controller
{
private $userService;
private $notificationService;
public function __construct(
UserService $userService,
NotificationService $notificationService
) {
$this->userService = $userService;
$this->notificationService = $notificationService;
}
public function create(Request $request): Response
{
$input = $request->getParsedBody();
try {
$user = $this->userService->createUser($input);
$this->notificationService->sendWelcomeEmail($user);
return $this->successResponse($user, 'สร้างผู้ใช้สำเร็จ');
} catch (ValidationException $e) {
return $this->errorResponse('ข้อมูลไม่ถูกต้อง', 422, $e->getErrors());
}
}
}3. Response Consistency
trait ApiResponseTrait
{
$code = 20; // 0): Response
{
return Response::create()
->withHeader('Content-Type', 'application/json')
->withStatus($code)
->getBody()->write(json_encode([
'success' => true,
'message' => $message,
'data' => $data,
'timestamp' => time()
]));
}
$code = 40; // 0, $errors = null): Response
{
$response = [
'success' => false,
'message' => $message,
'timestamp' => time()
];
if ($errors !== null) {
$response['errors'] = $errors;
}
return Response::create()
->withHeader('Content-Type', 'application/json')
->withStatus($code)
->getBody()->write(json_encode($response));
}
protected function paginatedResponse(array $data, int $total, int $page, int $limit): Response
{
return $this->successResponse([
'items' => $data,
'pagination' => [
'current_page' => $page,
'per_page' => $limit,
'total' => $total,
'total_pages' => ceil($total / $limit),
'has_next' => $page < ceil($total / $limit),
'has_prev' => $page > 1
]
]);
}
}4. Error Handling
class BaseController extends Controller
{
protected function handleException(Exception $e, Request $request): Response
{
// Log error
error_log("Controller Error: " . $e->getMessage());
// ตรวจสอบประเภท exception
if ($e instanceof ValidationException) {
return $this->errorResponse('ข้อมูลไม่ถูกต้อง', 422, $e->getErrors());
}
if ($e instanceof AuthenticationException) {
return $this->errorResponse('ไม่ได้รับอนุญาต', 401);
}
if ($e instanceof NotFoundException) {
return $this->errorResponse('ไม่พบข้อมูล', 404);
}
// Error ทั่วไป
$message = self::$cfg->debug ? $e->getMessage() : 'เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์';
return $this->errorResponse($message, 500);
}
}5. Performance Optimization
use Kotchasan\Database;
class OptimizedController extends Controller
{
/
ใช้ Cache สำหรับข้อมูลที่ไม่เปลี่ยนแปลงบ่อย
/
public function getCategories(Request $request): Response
{
$cache = CacheFactory::create('file');
$cacheKey = 'categories_list';
$categories = $cache->get($cacheKey);
if ($categories === null) {
$categories = Kotchasan\Database::create()
->select(['id', 'name', 'slug'])
->from('categories')
->where(['status', 'active'])
->orderBy('name')
->fetchAll();
$cache->set($cacheKey, $categories, 3600); // Cache 1 ชั่วโมง
}
return $this->successResponse($categories);
}
/
ใช้ Eager Loading เพื่อลด N+1 queries
/
public function getUsersWithProfiles(Request $request): Response
{
// แทนที่จะ query แยกสำหรับแต่ละ user
$users = Kotchasan\Database::create()
->select([
'U.id', 'U.name', 'U.email',
'P.phone', 'P.address', 'P.avatar'
])
->from('users U')
->leftJoin('user_profiles P', 'U.id = P.user_id')
->where(['U.status', 'active'])
->fetchAll();
return $this->successResponse($users);
}
}Controller Classes ใน Kotchasan Framework ให้ความยืดหยุ่นในการจัดการ HTTP requests และสร้าง API endpoints ที่มีประสิทธิภาพ การใช้งานที่ถูกต้องจะช่วยให้โค้ดมีความเป็นระเบียบและง่ายต่อการบำรุงรักษา