Encapsular la API de OpenWeatherMap en una fuente de datos
1Introducción
En este tutorial, veremos cómo crear un objeto que se pueda usar como fuente de datos. Como ejemplo, vamos a crear un objeto que se conecta a la API del servicio OpenWeatherMap, lo que permite obtener el tiempo actual de cualquier ubicación (para ser precisos, la API de OpenWeatherMap recibe una latitud y una longitud como parámetros; por eso usaremos la API de Geocodificación para obtener las coordenadas geográficas de la ciudad solicitada).
2Configuración
En el archivo de configuración etc/temma.php, vamos a añadir la definición de una fuente de datos un tanto especial. Como no es una fuente de datos gestionada de forma nativa por Temma, vamos a anteponer al DSN el nombre del objeto que se va a usar (entre corchetes).
El DSN tendrá la forma openweather://API_KEY
siendo API_KEY la clave de API proporcionada por OpenWeatherMap.
Ejemplo de configuración:
<?php
return [
"application" => [
"dataSources" => [
"meteo" => '[\OpenWeatherMap\Weather]openweather://0123456789abcdef0123456789abcdef'
]
]
];
3Código fuente
Aquí está el código de nuestra fuente de datos, que guardaremos en el archivo lib/OpenWeatherMap/Weather.php:
<?php
namespace OpenWeatherMap;
class Weather extends \Temma\Base\Datasource {
/** Constante: prefijo del DSN. */
const DSN_SCHEME = 'weather://';
/** Constante: URL de la API de datos de OpenWeatherMap. */
const DATA_API_URL = 'https://api.openweathermap.org/data/2.5/weather';
/** Constante: URL de la API de geocodificación de OpenWeatherMap. */
const GEO_API_URL = 'http://api.openweathermap.org/geo/1.0/direct';
/** Clave de acceso a la API. */
private $_key = null;
/**
* Fábrica. Crea una instancia del objeto a partir de un DSN.
* @param string $dsn Cadena de configuración.
* @return \OpenWeatherMap\Weather El objeto instanciado.
* @throws \Exception Si el DSN es incorrecto.
*/
static public function factory(string $dsn) : \OpenWeatherMap\Weather {
if (!str_starts_with($dsn, self::DSN_SCHEME)) {
throw new \Exception("Invalid OpenWeatherMap DSN '$dsn'.");
}
$key = mb_substr($dsn, mb_strlen(self::DSN_SCHEME));
return (new self($key));
}
/**
* Constructor.
* @param string $key Clave de acceso a la API.
*/
public function __construct(string $key) {
$this->_key = $key;
}
/**
* Obtiene el tiempo de una ubicación.
* @param string $place Ubicación, en el formato "Ciudad" o "Ciudad, País" o "Ciudad, Región, País".
* @param mixed $default Parámetro no utilizado (necesario por razones de herencia).
* @param mixed $options Parámetro no utilizado (necesario por razones de herencia).
* @return mixed Array asociativo con los datos meteorológicos.
* @throws \Exception Si se ha producido un error.
*/
public function get(string $place, mixed $default=null, mixed $options=null) : mixed {
// obtención de los datos geográficos
$query = http_build_query([
'appid' => $this->_key,
'limit' => 1,
'q' => $place,
]);
$result = file_get_contents(self::GEO_API_URL . '?' . $query);
$geo = json_decode($result, true);
if (!isset($geo[0]['lat']) || !isset($geo[0]['lon'])) {
throw new \Exception("Unable to get geographic data for '$place'.");
}
// obtención de los datos meteorológicos
$query = http_build_query([
'appid' => $this->_key,
'lat' => $geo[0]['lat'],
'lon' => $geo[0]['lon'],
'units' => 'metric',
]);
$result = file_get_contents(self::DATA_API_URL . '?' . $query);
$weather = json_decode($result, true);
if (!isset($weather['main']['temp']))
throw new \Exception("Unable to get weather data for '$place'.");
return [
'temperature' => $weather['main']['temp'],
'perceived' => $weather['main']['feels_like'],
'pressure' => $weather['main']['pressure'],
'humidity' => $weather['main']['humidity'],
];
}
}
- Líneas 21 a 27: método factory(), llamado por Temma cuando se crea la fuente de datos. Este método interpreta el DSN y llama al constructor.
- Líneas 32 a 34: constructor, usado para crear una instancia del objeto directamente.
- Líneas 43 a 72: método get(), que sobrescribe el método get() del objeto padre \Temma\Base\Datasource. Este método se puede usar directamente, pero también se llama automáticamente cuando se lee como un array.
- Líneas 45 a 54: conexión con la API de Geocodificación, para obtener la latitud y la longitud de la ciudad solicitada.
- Líneas 56 a 65: conexión con la API de OpenWeatherMap, para obtener la información meteorológica a partir de la latitud y la longitud obtenidas previamente.
4Uso
En un controlador, la fuente de datos llamada "meteo" en el archivo de configuración está disponible
escribiendo $this->meteo. La información meteorológica se puede obtener llamando al método
get() o usándola como un array:
// usando el método get()
$data = $this->meteo->get('Paris, FR');
// escritura como array
$data = $this->meteo['Paris, FR'];
En otro objeto, debes usar el componente de inyección de dependencias:
$data = $this->_loader->dataSources->meteo->get('Paris, FR');
$data = $this->_loader->dataSources->meteo['Paris, FR'];
Los datos obtenidos se almacenan en un array asociativo:
printf(" Temperatura medida: %f °C\n", $data['temperature']);
printf(" Sensación térmica: %f °C\n", $data['perceived']);
printf("Presión atmosférica: %f hPa\n", $data['pressure']);
printf(" Humedad: %f %%\n", $data['humidity']);