From 5458e0c4458459667269ed75426a963967a43b88 Mon Sep 17 00:00:00 2001 From: Damien Tardy-Panis Date: Thu, 6 Oct 2016 15:56:27 +0200 Subject: [PATCH 1/2] add support to get current weather for a group of city ids --- Cmfcmf/OpenWeatherMap.php | 72 ++++++++++++++ Cmfcmf/OpenWeatherMap/CurrentWeather.php | 52 +++++++--- Cmfcmf/OpenWeatherMap/CurrentWeatherGroup.php | 95 +++++++++++++++++++ 3 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 Cmfcmf/OpenWeatherMap/CurrentWeatherGroup.php diff --git a/Cmfcmf/OpenWeatherMap.php b/Cmfcmf/OpenWeatherMap.php index e60ba1b..baf6429 100644 --- a/Cmfcmf/OpenWeatherMap.php +++ b/Cmfcmf/OpenWeatherMap.php @@ -19,6 +19,7 @@ use Cmfcmf\OpenWeatherMap\AbstractCache; use Cmfcmf\OpenWeatherMap\CurrentWeather; +use Cmfcmf\OpenWeatherMap\CurrentWeatherGroup; use Cmfcmf\OpenWeatherMap\Exception as OWMException; use Cmfcmf\OpenWeatherMap\Fetcher\CurlFetcher; use Cmfcmf\OpenWeatherMap\Fetcher\FetcherInterface; @@ -46,6 +47,11 @@ class OpenWeatherMap */ private $weatherUrl = 'http://api.openweathermap.org/data/2.5/weather?'; + /** + * @var string The basic api url to fetch weather group data from. + */ + private $weatherGroupUrl = 'http://api.openweathermap.org/data/2.5/group?'; + /** * @var string The basic api url to fetch weekly forecast data from. */ @@ -182,6 +188,29 @@ public function getWeather($query, $units = 'imperial', $lang = 'en', $appid = ' return new CurrentWeather($xml, $units); } + /** + * Returns the current weather for a group of city ids. + * + * @param array $ids The city ids to get weather information for + * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned. + * @param string $lang The language to use for descriptions, default is 'en'. For possible values see http://openweathermap.org/current#multi. + * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details. + * + * @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error. + * @throws \InvalidArgumentException If an argument error occurs. + * + * @return Array Array of CurrentWeather objects. + * + * @api + */ + public function getWeatherGroup($ids, $units = 'imperial', $lang = 'en', $appid = '') + { + $answer = $this->getRawWeatherGroupData($ids, $units, $lang, $appid); + $json = $this->parseJson($answer); + + return new CurrentWeatherGroup($json, $units); + } + /** * Returns the forecast for the place you specified. DANGER: Might return * fewer results than requested due to a bug in the OpenWeatherMap API! @@ -296,6 +325,28 @@ public function getRawWeatherData($query, $units = 'imperial', $lang = 'en', $ap return $this->cacheOrFetchResult($url); } + /** + * Directly returns the JSON string returned by OpenWeatherMap for the group of current weather. + * Only a JSON response format is supported for this webservice. + * + * @param array $ids The city ids to get weather information for + * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned. + * @param string $lang The language to use for descriptions, default is 'en'. For possible values see http://openweathermap.org/current#multi. + * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details. + * + * @return string Returns false on failure and the fetched data in the format you specified on success. + * + * Warning: If an error occurs, OpenWeatherMap ALWAYS returns json data. + * + * @api + */ + public function getRawWeatherGroupData($ids, $units = 'imperial', $lang = 'en', $appid = '') + { + $url = $this->buildUrl($ids, $units, $lang, $appid, 'json', $this->weatherGroupUrl); + + return $this->cacheOrFetchResult($url); + } + /** * Directly returns the xml/json/html string returned by OpenWeatherMap for the hourly forecast. * @@ -468,6 +519,8 @@ private function buildQueryUrlParameter($query) switch ($query) { case is_array($query) && isset($query['lat']) && isset($query['lon']) && is_numeric($query['lat']) && is_numeric($query['lon']): return "lat={$query['lat']}&lon={$query['lon']}"; + case is_array($query) && is_numeric($query[0]): + return 'id='.implode(',', $query); case is_numeric($query): return "id=$query"; case is_string($query): @@ -501,4 +554,23 @@ private function parseXML($answer) } } } + + /** + * @param string $answer The content returned by OpenWeatherMap. + * + * @return \stdClass + * @throws OWMException If the content isn't valid JSON. + */ + private function parseJson($answer) + { + $json = json_decode($answer); + + if (json_last_error() !== JSON_ERROR_NONE) + { + throw new OWMException('OpenWeatherMap returned an invalid json object: ' . json_last_error_msg()); + } + + return $json; + } + } diff --git a/Cmfcmf/OpenWeatherMap/CurrentWeather.php b/Cmfcmf/OpenWeatherMap/CurrentWeather.php index 7ce2e2a..ba05509 100644 --- a/Cmfcmf/OpenWeatherMap/CurrentWeather.php +++ b/Cmfcmf/OpenWeatherMap/CurrentWeather.php @@ -87,31 +87,53 @@ class CurrentWeather /** * Create a new weather object. * - * @param \SimpleXMLElement $xml - * @param string $units + * @param mixed $data + * @param string $units * * @internal */ - public function __construct(\SimpleXMLElement $xml, $units) + public function __construct($data, $units) { - $this->city = new City($xml->city['id'], $xml->city['name'], $xml->city->coord['lon'], $xml->city->coord['lat'], $xml->city->country); - $this->temperature = new Temperature(new Unit($xml->temperature['value'], $xml->temperature['unit']), new Unit($xml->temperature['min'], $xml->temperature['unit']), new Unit($xml->temperature['max'], $xml->temperature['unit'])); - $this->humidity = new Unit($xml->humidity['value'], $xml->humidity['unit']); - $this->pressure = new Unit($xml->pressure['value'], $xml->pressure['unit']); - - // This is kind of a hack, because the units are missing in the xml document. + // This is kind of a hack, because the units are missing in the document. if ($units == 'metric') { $windSpeedUnit = 'm/s'; } else { $windSpeedUnit = 'mph'; } - $this->wind = new Wind(new Unit($xml->wind->speed['value'], $windSpeedUnit, $xml->wind->speed['name']), new Unit($xml->wind->direction['value'], $xml->wind->direction['code'], $xml->wind->direction['name'])); - $this->clouds = new Unit($xml->clouds['value'], null, $xml->clouds['name']); - $this->precipitation = new Unit($xml->precipitation['value'], $xml->precipitation['unit'], $xml->precipitation['mode']); $utctz = new \DateTimeZone('UTC'); - $this->sun = new Sun(new \DateTime($xml->city->sun['rise'], $utctz), new \DateTime($xml->city->sun['set'], $utctz)); - $this->weather = new WeatherObj($xml->weather['number'], $xml->weather['value'], $xml->weather['icon']); - $this->lastUpdate = new \DateTime($xml->lastupdate['value'], $utctz); + + if ($data instanceof \SimpleXMLElement) { + $this->city = new City($data->city['id'], $data->city['name'], $data->city->coord['lon'], $data->city->coord['lat'], $data->city->country); + $this->temperature = new Temperature(new Unit($data->temperature['value'], $data->temperature['unit']), new Unit($data->temperature['min'], $data->temperature['unit']), new Unit($data->temperature['max'], $data->temperature['unit'])); + $this->humidity = new Unit($data->humidity['value'], $data->humidity['unit']); + $this->pressure = new Unit($data->pressure['value'], $data->pressure['unit']); + $this->wind = new Wind(new Unit($data->wind->speed['value'], $windSpeedUnit, $data->wind->speed['name']), new Unit($data->wind->direction['value'], $data->wind->direction['code'], $data->wind->direction['name'])); + $this->clouds = new Unit($data->clouds['value'], null, $data->clouds['name']); + $this->precipitation = new Unit($data->precipitation['value'], $data->precipitation['unit'], $data->precipitation['mode']); + $this->sun = new Sun(new \DateTime($data->city->sun['rise'], $utctz), new \DateTime($data->city->sun['set'], $utctz)); + $this->weather = new WeatherObj($data->weather['number'], $data->weather['value'], $data->weather['icon']); + $this->lastUpdate = new \DateTime($data->lastupdate['value'], $utctz); + + } else { + $this->city = new City($data->id, $data->name, $data->coord->lon, $data->coord->lat, $data->sys->country); + $this->temperature = new Temperature(new Unit($data->main->temp, $units), new Unit($data->main->temp_min, $units), new Unit($data->main->temp_max, $units)); + $this->humidity = new Unit($data->main->humidity, '%'); + $this->pressure = new Unit($data->main->pressure, 'hPa'); + $this->wind = new Wind(new Unit($data->wind->speed, $windSpeedUnit), new Unit($data->wind->deg)); + $this->clouds = new Unit($data->clouds->all, '%'); + + // the rain field is not always present in the JSON response + // and sometimes it contains the field '1h', sometimes the field '3h' + $rain = isset($data->rain) ? (array) $data->rain : []; + $rainUnit = !empty($rain) ? key($rain) : ''; + $rainValue = !empty($rain) ? current($rain) : 0.0; + $this->precipitation = new Unit($rainValue, $rainUnit); + + $this->sun = new Sun(\DateTime::createFromFormat('U', $data->sys->sunrise, $utctz), \DateTime::createFromFormat('U', $data->sys->sunset, $utctz)); + $this->weather = new WeatherObj($data->weather[0]->id, $data->weather[0]->description, $data->weather[0]->icon); + $this->lastUpdate = \DateTime::createFromFormat('U', $data->dt, $utctz); + } } + } diff --git a/Cmfcmf/OpenWeatherMap/CurrentWeatherGroup.php b/Cmfcmf/OpenWeatherMap/CurrentWeatherGroup.php new file mode 100644 index 0000000..b4e346d --- /dev/null +++ b/Cmfcmf/OpenWeatherMap/CurrentWeatherGroup.php @@ -0,0 +1,95 @@ +list as $currentWeather) { + $this->currentWeathers[] = new CurrentWeather($currentWeather, $units); + } + } + + /** + * @internal + */ + public function rewind() + { + $this->position = 0; + } + + /** + * @internal + */ + public function current() + { + return $this->currentWeathers[$this->position]; + } + + /** + * @internal + */ + public function key() + { + return $this->current()->city->id; + } + + /** + * @internal + */ + public function next() + { + ++$this->position; + } + + /** + * @internal + */ + public function valid() + { + return isset($this->currentWeathers[$this->position]); + } +} From 6c444d711df2ed88b305b8805075f20fe44d1141 Mon Sep 17 00:00:00 2001 From: Christian Flach Date: Mon, 17 Oct 2016 11:59:04 +0200 Subject: [PATCH 2/2] A bit of formatting. --- Cmfcmf/OpenWeatherMap.php | 6 +----- Cmfcmf/OpenWeatherMap/CurrentWeather.php | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Cmfcmf/OpenWeatherMap.php b/Cmfcmf/OpenWeatherMap.php index baf6429..bfcec6f 100644 --- a/Cmfcmf/OpenWeatherMap.php +++ b/Cmfcmf/OpenWeatherMap.php @@ -336,8 +336,6 @@ public function getRawWeatherData($query, $units = 'imperial', $lang = 'en', $ap * * @return string Returns false on failure and the fetched data in the format you specified on success. * - * Warning: If an error occurs, OpenWeatherMap ALWAYS returns json data. - * * @api */ public function getRawWeatherGroupData($ids, $units = 'imperial', $lang = 'en', $appid = '') @@ -564,9 +562,7 @@ private function parseXML($answer) private function parseJson($answer) { $json = json_decode($answer); - - if (json_last_error() !== JSON_ERROR_NONE) - { + if (json_last_error() !== JSON_ERROR_NONE) { throw new OWMException('OpenWeatherMap returned an invalid json object: ' . json_last_error_msg()); } diff --git a/Cmfcmf/OpenWeatherMap/CurrentWeather.php b/Cmfcmf/OpenWeatherMap/CurrentWeather.php index ba05509..4f766a2 100644 --- a/Cmfcmf/OpenWeatherMap/CurrentWeather.php +++ b/Cmfcmf/OpenWeatherMap/CurrentWeather.php @@ -114,7 +114,6 @@ public function __construct($data, $units) $this->sun = new Sun(new \DateTime($data->city->sun['rise'], $utctz), new \DateTime($data->city->sun['set'], $utctz)); $this->weather = new WeatherObj($data->weather['number'], $data->weather['value'], $data->weather['icon']); $this->lastUpdate = new \DateTime($data->lastupdate['value'], $utctz); - } else { $this->city = new City($data->id, $data->name, $data->coord->lon, $data->coord->lat, $data->sys->country); $this->temperature = new Temperature(new Unit($data->main->temp, $units), new Unit($data->main->temp_min, $units), new Unit($data->main->temp_max, $units)); @@ -135,5 +134,4 @@ public function __construct($data, $units) $this->lastUpdate = \DateTime::createFromFormat('U', $data->dt, $utctz); } } - }