Files
weather/src/Application/Actions/Weather/GetWeatherAction.php
Oh 120dee172b
Some checks failed
Tests / Tests PHP 7.4 (push) Has been cancelled
Tests / Tests PHP 8 (push) Has been cancelled
Tests / Tests PHP 8.1 (push) Has been cancelled
PKG
2025-09-04 14:47:18 +02:00

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