Encapsulando a API do OpenWeatherMap em uma Fonte de Dados
1Introdução
Neste tutorial, vamos ver como criar um objeto que pode ser usado como fonte de dados. Como exemplo, vamos criar um objeto que se conecta à API do serviço OpenWeatherMap, permitindo obter a previsão do tempo atual para qualquer localidade (para ser preciso, a API do OpenWeatherMap recebe uma latitude e uma longitude como parâmetros; por isso, vamos usar a API de Geocodificação para obter as coordenadas geográficas da cidade solicitada).
2Configuração
No arquivo de configuração etc/temma.php, vamos adicionar a definição de uma fonte de dados um pouco especial. Como não é uma fonte de dados gerenciada nativamente pelo Temma, vamos prefixar o DSN com o nome do objeto a ser usado (entre colchetes).
O DSN terá a forma openweather://API_KEY
sendo API_KEY a chave de API fornecida pelo OpenWeatherMap.
Exemplo de configuração:
<?php
return [
"application" => [
"dataSources" => [
"meteo" => '[\OpenWeatherMap\Weather]openweather://0123456789abcdef0123456789abcdef'
]
]
];
3Código-fonte
Aqui está o código da nossa fonte de dados, que vamos salvar no arquivo lib/OpenWeatherMap/Weather.php:
<?php
namespace OpenWeatherMap;
class Weather extends \Temma\Base\Datasource {
/** Constante: prefixo do DSN. */
const DSN_SCHEME = 'weather://';
/** Constante: URL da API de dados do OpenWeatherMap. */
const DATA_API_URL = 'https://api.openweathermap.org/data/2.5/weather';
/** Constante: URL da API de geocodificação do OpenWeatherMap. */
const GEO_API_URL = 'http://api.openweathermap.org/geo/1.0/direct';
/** Chave de acesso à API. */
private $_key = null;
/**
* Fábrica. Cria uma instância do objeto a partir de um DSN.
* @param string $dsn String de configuração.
* @return \OpenWeatherMap\Weather O objeto instanciado.
* @throws \Exception Se o DSN estiver incorreto.
*/
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));
}
/**
* Construtor.
* @param string $key Chave de acesso à API.
*/
public function __construct(string $key) {
$this->_key = $key;
}
/**
* Obtém a previsão do tempo de uma localidade.
* @param string $place Localidade, no formato "Cidade" ou "Cidade, País" ou "Cidade, Região, País".
* @param mixed $default Parâmetro não utilizado (necessário por motivos de herança).
* @param mixed $options Parâmetro não utilizado (necessário por motivos de herança).
* @return mixed Array associativo contendo os dados meteorológicos.
* @throws \Exception Se ocorreu um erro.
*/
public function get(string $place, mixed $default=null, mixed $options=null) : mixed {
// obtenção dos dados 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'.");
}
// obtenção dos dados 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'],
];
}
}
- Linhas 21 a 27: método factory(), chamado pelo Temma quando a fonte de dados é criada. Esse método interpreta o DSN e chama o construtor.
- Linhas 32 a 34: construtor, usado para criar uma instância do objeto diretamente.
- Linhas 43 a 72: método get(), que sobrescreve o método get() do objeto pai \Temma\Base\Datasource. Esse método pode ser usado diretamente, mas também é chamado automaticamente quando lido como um array.
- Linhas 45 a 54: conexão com a API de Geocodificação, para obter a latitude e a longitude da cidade solicitada.
- Linhas 56 a 65: conexão com a API do OpenWeatherMap, para obter as informações meteorológicas a partir da latitude e da longitude obtidas anteriormente.
4Uso
Em um controlador, a fonte de dados chamada "meteo" no arquivo de configuração está disponível
escrevendo $this->meteo. As informações meteorológicas podem ser obtidas chamando o
método get() ou usando-a como um array:
// usando o método get()
$data = $this->meteo->get('Paris, FR');
// escrita como array
$data = $this->meteo['Paris, FR'];
Em outro objeto, você precisa usar o componente de injeção de dependências:
$data = $this->_loader->dataSources->meteo->get('Paris, FR');
$data = $this->_loader->dataSources->meteo['Paris, FR'];
Os dados obtidos são armazenados em um array associativo:
printf(" Temperatura medida: %f °C\n", $data['temperature']);
printf(" Sensação térmica: %f °C\n", $data['perceived']);
printf(" Pressão atmosférica: %f hPa\n", $data['pressure']);
printf(" Umidade: %f %%\n", $data['humidity']);