Files
api-btekno/src/Modules/Retribusi/Frontend/LocationController.php
mwpn 4d36f02f32 feat: tambah endpoint frontend dan field camera di gate
- Tambah endpoint GET /tariffs (list tariffs)
- Tambah endpoint GET /locations/{code} (detail location)
- Tambah endpoint GET /gates/{location_code}/{gate_code} (detail gate)
- Tambah endpoint GET /tariffs/{location_code}/{gate_code}/{category} (detail tariff)
- Tambah endpoint GET /audit-logs (audit trail history)
- Tambah endpoint GET /entry-events (raw entry events)
- Tambah endpoint GET /realtime/events (realtime events list)
- Tambah field camera di gates (support HLS, RTSP, HTTP streaming)
- Migration 004: add camera column to gates table
- Update validasi dan service untuk support camera field
2025-12-18 06:36:49 +07:00

389 lines
11 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Modules\Retribusi\Frontend;
use App\Support\ResponseHelper;
use App\Support\Validator;
use PDOException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class LocationController
{
private RetribusiReadService $readService;
private RetribusiWriteService $writeService;
private AuditService $auditService;
public function __construct(
RetribusiReadService $readService,
RetribusiWriteService $writeService,
AuditService $auditService
) {
$this->readService = $readService;
$this->writeService = $writeService;
$this->auditService = $auditService;
}
public function getLocations(
ServerRequestInterface $request,
ResponseInterface $response
): ResponseInterface {
$queryParams = $request->getQueryParams();
[$page, $limit] = Validator::validatePagination($queryParams);
$data = $this->readService->getLocations($page, $limit);
$total = $this->readService->getLocationsTotal();
return ResponseHelper::json(
$response,
[
'success' => true,
'data' => $data,
'meta' => [
'page' => $page,
'limit' => $limit,
'total' => $total,
'pages' => (int) ceil($total / $limit)
],
'timestamp' => time()
]
);
}
public function getLocation(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$code = $args['code'] ?? null;
if ($code === null || !is_string($code)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['code' => 'Invalid location code']
],
422
);
}
$data = $this->writeService->getLocation($code);
if ($data === null) {
return ResponseHelper::json(
$response,
[
'error' => 'not_found',
'message' => 'Location not found'
],
404
);
}
return ResponseHelper::json(
$response,
[
'success' => true,
'data' => $data,
'timestamp' => time()
]
);
}
public function createLocation(
ServerRequestInterface $request,
ResponseInterface $response
): ResponseInterface {
$body = $request->getParsedBody();
if (!is_array($body)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['body' => 'Invalid JSON body']
],
422
);
}
$errors = Validator::validateLocation($body, false);
if (!empty($errors)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => $errors
],
422
);
}
try {
// Check if location already exists
$existing = $this->writeService->getLocation($body['code']);
if ($existing !== null) {
return ResponseHelper::json(
$response,
[
'error' => 'conflict',
'message' => 'Location with this code already exists'
],
409
);
}
// Create location
$data = $this->writeService->createLocation($body);
// Audit log
$serverParams = $request->getServerParams();
$this->auditService->log(
(int) $request->getAttribute('user_id'),
$request->getAttribute('username', ''),
$request->getAttribute('role', ''),
'create',
'locations',
$body['code'],
null,
$data,
AuditService::getClientIp($serverParams),
$serverParams['HTTP_USER_AGENT'] ?? null
);
return ResponseHelper::json(
$response,
[
'success' => true,
'data' => $data,
'timestamp' => time()
],
201
);
} catch (PDOException $e) {
// Check for unique constraint violation
if ($e->getCode() === '23000') {
return ResponseHelper::json(
$response,
[
'error' => 'conflict',
'message' => 'Location with this code already exists'
],
409
);
}
return ResponseHelper::json(
$response,
[
'error' => 'server_error',
'message' => 'Database error occurred'
],
500
);
}
}
public function updateLocation(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$code = $args['code'] ?? null;
if ($code === null || !is_string($code)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['code' => 'Invalid location code']
],
422
);
}
$body = $request->getParsedBody();
if (!is_array($body)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['body' => 'Invalid JSON body']
],
422
);
}
// Prevent changing code
if (isset($body['code']) && $body['code'] !== $code) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['code' => 'Code is immutable']
],
422
);
}
$errors = Validator::validateLocation($body, true);
if (!empty($errors)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => $errors
],
422
);
}
try {
// Check if location exists
$before = $this->writeService->getLocation($code);
if ($before === null) {
return ResponseHelper::json(
$response,
[
'error' => 'not_found',
'message' => 'Location not found'
],
404
);
}
// Update location
$after = $this->writeService->updateLocation($code, $body);
if ($after === null) {
return ResponseHelper::json(
$response,
[
'error' => 'not_found',
'message' => 'Location not found'
],
404
);
}
// Audit log
$serverParams = $request->getServerParams();
$this->auditService->log(
(int) $request->getAttribute('user_id'),
$request->getAttribute('username', ''),
$request->getAttribute('role', ''),
'update',
'locations',
$code,
$before,
$after,
AuditService::getClientIp($serverParams),
$serverParams['HTTP_USER_AGENT'] ?? null
);
return ResponseHelper::json(
$response,
[
'success' => true,
'data' => $after,
'timestamp' => time()
]
);
} catch (PDOException $e) {
return ResponseHelper::json(
$response,
[
'error' => 'server_error',
'message' => 'Database error occurred'
],
500
);
}
}
public function deleteLocation(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$code = $args['code'] ?? null;
if ($code === null || !is_string($code)) {
return ResponseHelper::json(
$response,
[
'error' => 'validation_error',
'fields' => ['code' => 'Invalid location code']
],
422
);
}
try {
// Check if location exists
$before = $this->writeService->getLocation($code);
if ($before === null) {
return ResponseHelper::json(
$response,
[
'error' => 'not_found',
'message' => 'Location not found'
],
404
);
}
// Soft delete
$deleted = $this->writeService->deleteLocation($code);
if (!$deleted) {
return ResponseHelper::json(
$response,
[
'error' => 'server_error',
'message' => 'Failed to delete location'
],
500
);
}
// Get after state (is_active=0)
$after = $this->writeService->getLocation($code);
// Audit log
$serverParams = $request->getServerParams();
$this->auditService->log(
(int) $request->getAttribute('user_id'),
$request->getAttribute('username', ''),
$request->getAttribute('role', ''),
'delete',
'locations',
$code,
$before,
$after,
AuditService::getClientIp($serverParams),
$serverParams['HTTP_USER_AGENT'] ?? null
);
return ResponseHelper::json(
$response,
[
'success' => true,
'data' => ['deleted' => true],
'timestamp' => time()
]
);
} catch (PDOException $e) {
return ResponseHelper::json(
$response,
[
'error' => 'server_error',
'message' => 'Database error occurred'
],
500
);
}
}
}