100 lines
3.6 KiB
PHP
100 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Ohrionmartin\Weather\Application\Actions\Weather;
|
|
|
|
use Ohrionmartin\Weather\Service\OpenWeatherClient;
|
|
use Psr\Http\Message\ResponseInterface as Response;
|
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
|
|
final class GetWeatherAction
|
|
{
|
|
private OpenWeatherClient $ow;
|
|
|
|
/**
|
|
* GetWeatherAction constructor.
|
|
*
|
|
* @param OpenWeatherClient $ow OpenWeather API client used to fetch weather and perform geocoding
|
|
*/
|
|
public function __construct(OpenWeatherClient $ow)
|
|
{
|
|
$this->ow = $ow;
|
|
}
|
|
|
|
/**
|
|
* Handle GET /weather requests.
|
|
*
|
|
* Supports:
|
|
* - city: string city name (uses OpenWeather Geocoding API to resolve to coordinates)
|
|
* - lat, lon: floats for direct coordinate queries
|
|
* - exclude: comma-separated parts to exclude (current, minutely, hourly, daily,alerts)
|
|
* - units: standard|metric|imperial
|
|
* - lang: locale code (e.g., en, es)
|
|
*
|
|
* If "city" is provided, lat/lon are not required. Otherwise, lat and lon must be provided.
|
|
*
|
|
* @param Request $request PSR-7 Server Request
|
|
* @param Response $response PSR-7 Response
|
|
* @return Response JSON response with weather data or error payload
|
|
*/
|
|
public function __invoke(Request $request, Response $response): Response
|
|
{
|
|
$params = $request->getQueryParams();
|
|
|
|
$city = isset($params['city']) ? trim((string)$params['city']) : null;
|
|
|
|
$exclude = isset($params['exclude']) ? (string) $params['exclude'] : null;
|
|
$units = isset($params['units']) ? (string) $params['units'] : null; // standard|metric|imperial
|
|
$lang = isset($params['lang']) ? (string) $params['lang'] : null;
|
|
|
|
try {
|
|
if ($city !== null && $city !== '') {
|
|
$data = $this->ow->oneCallByCity($city, [
|
|
'exclude' => $exclude,
|
|
'units' => $units,
|
|
'lang' => $lang,
|
|
]);
|
|
return $this->json($response, $data, 200);
|
|
}
|
|
|
|
// Validate required parameters if city not provided
|
|
if (!isset($params['lat'], $params['lon'])) {
|
|
return $this->json($response, ['error' => 'city or lat/lon are required'], 400);
|
|
}
|
|
|
|
$lat = filter_var($params['lat'], FILTER_VALIDATE_FLOAT);
|
|
$lon = filter_var($params['lon'], FILTER_VALIDATE_FLOAT);
|
|
|
|
if ($lat === false || $lon === false || $lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
|
return $this->json($response, ['error' => 'lat/lon are invalid'], 422);
|
|
}
|
|
|
|
$data = $this->ow->oneCall((float)$lat, (float)$lon, [
|
|
'exclude' => $exclude,
|
|
'units' => $units,
|
|
'lang' => $lang,
|
|
]);
|
|
return $this->json($response, $data, 200);
|
|
} catch (\RuntimeException $e) {
|
|
return $this->json($response, ['error' => $e->getMessage()], 502);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write a JSON payload to the response with a given status code.
|
|
*
|
|
* @param Response $response Response to write into
|
|
* @param array<string,mixed> $data Data to JSON-encode
|
|
* @param int $status HTTP status code
|
|
* @return Response
|
|
*/
|
|
private function json(Response $response, array $data, int $status): Response
|
|
{
|
|
$response->getBody()->write(json_encode($data));
|
|
return $response
|
|
->withHeader('Content-Type', 'application/json')
|
|
->withStatus($status);
|
|
}
|
|
}
|