diff --git a/.gitignore b/.gitignore index 57872d0f..9253ae6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /vendor/ + +.idea/ diff --git a/src/Controller/ExchangeController.php b/src/Controller/ExchangeController.php new file mode 100644 index 00000000..93e17064 --- /dev/null +++ b/src/Controller/ExchangeController.php @@ -0,0 +1,57 @@ +exchangeService = $exchangeService; + $this->validator = $validator; + $this->common = $common; + } + + public function handle(string $requestUri): void + { + $segments = $this->common->getExtractSegments($requestUri); + + $validation = $this->validator->validate($segments); + + if ($validation['valid'] !== true) { + JsonResponse::send(['error' => $validation['message']], 400); + return; + } + + [$amount, $from, $to, $rate] = $validation['segments']; + + $result = $this->exchangeService->convert( + (float)$amount, + $from, + $to, + (float)$rate + ); + + if ($result === null) { + JsonResponse::send(['error' => 'Unsupported currency conversion.'], 400); + return; + } + + JsonResponse::send($result, 200); + } + + +} diff --git a/src/Domain/Currency.php b/src/Domain/Currency.php new file mode 100644 index 00000000..0875ed91 --- /dev/null +++ b/src/Domain/Currency.php @@ -0,0 +1,36 @@ + 'R$', + self::USD => '$', + self::EUR => '€', + ]; + + public static function isSupported(string $currency): bool + { + return in_array($currency, self::supported(), true); + } + + public static function supported(): array + { + return [ + self::BRL, + self::USD, + self::EUR, + ]; + } + + public static function getSymbol(string $currency): string + { + return self::SYMBOLS[$currency] ?? ''; + } +} \ No newline at end of file diff --git a/src/Http/JsonResponse.php b/src/Http/JsonResponse.php new file mode 100644 index 00000000..40f19dd8 --- /dev/null +++ b/src/Http/JsonResponse.php @@ -0,0 +1,15 @@ +isSupportedConversion($from, $to)) { + return null; + } + + return [ + 'valorConvertido' => $amount * $rate, + 'simboloMoeda' => Currency::getSymbol($to), + ]; + } + + private function isSupportedConversion(string $from, string $to): bool + { + $supportedConversions = [ + Currency::BRL . '-' . Currency::USD, + Currency::USD . '-' . Currency::BRL, + Currency::BRL . '-' . Currency::EUR, + Currency::EUR . '-' . Currency::BRL, + ]; + + return in_array($from . '-' . $to, $supportedConversions, true); + } +} \ No newline at end of file diff --git a/src/Utils/Url.php b/src/Utils/Url.php new file mode 100644 index 00000000..5e255ec5 --- /dev/null +++ b/src/Utils/Url.php @@ -0,0 +1,69 @@ +normalizeSegments($candidate); + + if (count($segments) >= 4) { + return array_slice($segments, -4); + } + + if ($segments !== []) { + return $segments; + } + } + + return []; + } + + private function normalizeSegments(string $value): array + { + $value = str_replace('index.php', '', $value); + $value = trim($value, " \t\n\r\0\x0B/"); + + if ($value === '') { + return []; + } + + return array_values(array_filter( + explode('/', $value), + static function (string $segment): bool { + return trim($segment) !== ''; + } + )); + } + + public function getExtractSegments(string $requestUri): array + { + return $this->extractSegments($requestUri); + + } +} \ No newline at end of file diff --git a/src/Validation/ExchangeRequestValidator.php b/src/Validation/ExchangeRequestValidator.php new file mode 100644 index 00000000..5bcce67c --- /dev/null +++ b/src/Validation/ExchangeRequestValidator.php @@ -0,0 +1,92 @@ + false, + 'message' => 'Invalid route parameters.', + 'debug' => $segments, + 'count' => count($segments), + ]; + } + + [$amount, $from, $to, $rate] = $segments; + + if (!$this->isValidPositiveNumber($amount)) { + return [ + 'valid' => false, + 'message' => 'Invalid amount.', + 'debug' => $segments, + ]; + } + + if (!$this->isValidCurrency($from)) { + return [ + 'valid' => false, + 'message' => 'Invalid source currency.', + 'debug' => $segments, + ]; + } + + if (!$this->isValidCurrency($to)) { + return [ + 'valid' => false, + 'message' => 'Invalid target currency.', + 'debug' => $segments, + ]; + } + + if (!$this->isValidPositiveNumber($rate)) { + return [ + 'valid' => false, + 'message' => 'Invalid rate.', + 'debug' => $segments, + ]; + } + + return [ + 'valid' => true, + 'segments' => $segments, + ]; + } + + private function isValidPositiveNumber(string $value): bool + { + if (!is_numeric($value)) { + return false; + } + + return (float) $value > 0; + } + + private function isValidCurrency(string $currency): bool + { + if (!preg_match('/^[A-Z]{3}$/', $currency)) { + return false; + } + + return Currency::isSupported($currency); + } +} \ No newline at end of file diff --git a/src/index.php b/src/index.php index 92841bc8..efea334e 100644 --- a/src/index.php +++ b/src/index.php @@ -16,3 +16,15 @@ require __DIR__ . '/../vendor/autoload.php'; +use App\Controller\ExchangeController; +use App\Service\ExchangeService; +use App\Validation\ExchangeRequestValidator; +use App\Utils\Url; + +$controller = new ExchangeController( + new ExchangeService(), + new ExchangeRequestValidator(), + new Url() +); + +$controller->handle($_SERVER['REQUEST_URI'] ?? '/'); \ No newline at end of file