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 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 ); } } }