Skip to content

Commit fdac750

Browse files
roelvanhintumcmfcmfRoel van Hintum
committed
Updated the UVIndex implementation (#132)
Co-authored-by: Christian Flach <cmfcmf.flach@gmail.com> Co-authored-by: Roel van Hintum <roel@born05.com>
1 parent 8a9b87f commit fdac750

File tree

6 files changed

+210
-146
lines changed

6 files changed

+210
-146
lines changed

.travis.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ language: php
55

66
matrix:
77
include:
8-
- php: hhvm
98
- php: nightly
9+
- php: 7.3
1010
- php: 7.2
1111
- php: 7.1
1212
- php: 7.0
@@ -19,11 +19,15 @@ matrix:
1919
allow_failures:
2020
- php: nightly
2121

22-
install:
23-
- if [[ ! $TRAVIS_PHP_VERSION = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi
24-
- if [[ ! $TRAVIS_PHP_VERSION = hhvm* ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi
22+
before_install:
23+
- phpenv config-rm xdebug.ini || echo "xdebug not available"
24+
- INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
2525
- echo date.timezone = Europe/Berlin >> $INI_FILE
2626
- echo memory_limit = -1 >> $INI_FILE
27+
28+
install:
29+
# Use composer update instead of composer install to install a working set of
30+
# dependencies on all PHP versions.
2731
- composer update
2832

2933
script:

Cmfcmf/OpenWeatherMap.php

Lines changed: 100 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class OpenWeatherMap
7171
/**
7272
* @var string The basic api url to fetch uv index data from.
7373
*/
74-
private $uvIndexUrl = 'https://api.openweathermap.org/v3/uvi';
74+
private $uvIndexUrl = 'https://api.openweathermap.org/data/2.5/uvi';
7575

7676
/**
7777
* @var AbstractCache|bool $cache The cache to use.
@@ -315,47 +315,73 @@ public function getWeatherHistory($query, \DateTime $start, $endOrCount = 1, $ty
315315
/**
316316
* Returns the current uv index at the location you specified.
317317
*
318-
* @param float $lat The location's latitude.
319-
* @param float $lon The location's longitude.
318+
* @param float $lat The location's latitude.
319+
* @param float $lon The location's longitude.
320320
*
321321
* @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
322322
* @throws \InvalidArgumentException If an argument error occurs.
323323
*
324-
* @return UVIndex The uvi object.
324+
* @return UVIndex
325325
*
326326
* @api
327327
*/
328328
public function getCurrentUVIndex($lat, $lon)
329329
{
330-
$answer = $this->getRawCurrentUVIndexData($lat, $lon);
330+
$answer = $this->getRawUVIndexData('current', $lat, $lon);
331331
$json = $this->parseJson($answer);
332332

333333
return new UVIndex($json);
334334
}
335335

336336
/**
337-
* Returns the uv index at date, time and location you specified.
337+
* Returns a forecast of the uv index at the specified location.
338+
* The optional $cnt parameter determines the number of days to forecase.
339+
* The maximum supported number of days is 8.
338340
*
339-
* @param float $lat The location's latitude.
340-
* @param float $lon The location's longitude.
341-
* @param \DateTimeInterface $dateTime The date and time to request data for.
342-
* @param string $timePrecision This decides about the timespan OWM will look for the uv index. The tighter
343-
* the timespan, the less likely it is to get a result. Can be 'year', 'month',
344-
* 'day', 'hour', 'minute' or 'second', defaults to 'day'.
341+
* @param float $lat The location's latitude.
342+
* @param float $lon The location's longitude.
343+
* @param int $cnt Number of returned days (default to 8).
345344
*
346345
* @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
347346
* @throws \InvalidArgumentException If an argument error occurs.
348347
*
349-
* @return UVIndex The uvi object.
348+
* @return UVIndex[]
350349
*
351350
* @api
352351
*/
353-
public function getUVIndex($lat, $lon, $dateTime, $timePrecision = 'day')
352+
public function getForecastUVIndex($lat, $lon, $cnt = 8)
354353
{
355-
$answer = $this->getRawUVIndexData($lat, $lon, $dateTime, $timePrecision);
356-
$json = $this->parseJson($answer);
354+
$answer = $this->getRawUVIndexData('forecast', $lat, $lon, $cnt);
355+
$data = $this->parseJson($answer);
357356

358-
return new UVIndex($json);
357+
return array_map(function ($entry) {
358+
return new UVIndex($entry);
359+
}, $data);
360+
}
361+
362+
/**
363+
* Returns the historic uv index at the specified location.
364+
*
365+
* @param float $lat The location's latitude.
366+
* @param float $lon The location's longitude.
367+
* @param \DateTime $start Starting point of time period.
368+
* @param \DateTime $end Final point of time period.
369+
*
370+
* @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
371+
* @throws \InvalidArgumentException If an argument error occurs.
372+
*
373+
* @return UVIndex[]
374+
*
375+
* @api
376+
*/
377+
public function getHistoricUVIndex($lat, $lon, $start, $end)
378+
{
379+
$answer = $this->getRawUVIndexData('historic', $lat, $lon, null, $start, $end);
380+
$data = $this->parseJson($answer);
381+
382+
return array_map(function ($entry) {
383+
return new UVIndex($entry);
384+
}, $data);
359385
}
360386

361387
/**
@@ -492,55 +518,45 @@ public function getRawWeatherHistory($query, \DateTime $start, $endOrCount = 1,
492518
}
493519

494520
/**
495-
* Directly returns the json string returned by OpenWeatherMap for the current UV index data.
521+
* Directly returns the json string returned by OpenWeatherMap for the UV index data.
496522
*
497-
* @param float $lat The location's latitude.
498-
* @param float $lon The location's longitude.
523+
* @param string $mode The type of requested data (['historic', 'forecast', 'current']).
524+
* @param float $lat The location's latitude.
525+
* @param float $lon The location's longitude.
526+
* @param int $cnt Number of returned days (only allowed for 'forecast' data).
527+
* @param \DateTime $start Starting point of time period (only allowed and required for 'historic' data).
528+
* @param \DateTime $end Final point of time period (only allowed and required for 'historic' data).
499529
*
500530
* @return bool|string Returns the fetched data.
501531
*
502532
* @api
503533
*/
504-
public function getRawCurrentUVIndexData($lat, $lon)
534+
public function getRawUVIndexData($mode, $lat, $lon, $cnt = null, $start = null, $end = null)
505535
{
506-
if (!$this->apiKey) {
507-
throw new \RuntimeException('Before using this method, you must set the api key using ->setApiKey()');
536+
if (!in_array($mode, array('current', 'forecast', 'historic'), true)) {
537+
throw new \InvalidArgumentException("$mode must be one of 'historic', 'forecast', 'current'.");
508538
}
509539
if (!is_float($lat) || !is_float($lon)) {
510540
throw new \InvalidArgumentException('$lat and $lon must be floating point numbers');
511541
}
512-
$url = $this->buildUVIndexUrl($lat, $lon);
513-
514-
return $this->cacheOrFetchResult($url);
515-
}
516-
517-
/**
518-
* Directly returns the json string returned by OpenWeatherMap for the UV index data.
519-
*
520-
* @param float $lat The location's latitude.
521-
* @param float $lon The location's longitude.
522-
* @param \DateTimeInterface $dateTime The date and time to request data for.
523-
* @param string $timePrecision This decides about the timespan OWM will look for the uv index. The tighter
524-
* the timespan, the less likely it is to get a result. Can be 'year', 'month',
525-
* 'day', 'hour', 'minute' or 'second', defaults to 'day'.
526-
*
527-
* @return bool|string Returns the fetched data.
528-
*
529-
* @api
530-
*/
531-
public function getRawUVIndexData($lat, $lon, $dateTime, $timePrecision = 'day')
532-
{
533-
if (!$this->apiKey) {
534-
throw new \RuntimeException('Before using this method, you must set the api key using ->setApiKey()');
542+
if (isset($cnt) && (!is_int($cnt) || $cnt > 8 || $cnt < 1)) {
543+
throw new \InvalidArgumentException('$cnt must be an int between 1 and 8');
535544
}
536-
if (!is_float($lat) || !is_float($lon)) {
537-
throw new \InvalidArgumentException('$lat and $lon must be floating point numbers');
545+
if (isset($start) && !$start instanceof \DateTime) {
546+
throw new \InvalidArgumentException('$start must be an instance of \DateTime');
547+
}
548+
if (isset($end) && !$end instanceof \DateTime) {
549+
throw new \InvalidArgumentException('$end must be an instance of \DateTime');
538550
}
539-
if (interface_exists('DateTimeInterface') && !$dateTime instanceof \DateTimeInterface || !$dateTime instanceof \DateTime) {
540-
throw new \InvalidArgumentException('$dateTime must be an instance of \DateTime or \DateTimeInterface');
551+
if ($mode === 'current' && (isset($start) || isset($end) || isset($cnt))) {
552+
throw new \InvalidArgumentException('Neither $start, $end, nor $cnt must be set for current data.');
553+
} elseif ($mode === 'forecast' && (isset($start) || isset($end) || !isset($cnt))) {
554+
throw new \InvalidArgumentException('$cnt needs to be set and both $start and $end must not be set for forecast data.');
555+
} elseif ($mode === 'historic' && (!isset($start) || !isset($end) || isset($cnt))) {
556+
throw new \InvalidArgumentException('Both $start and $end need to be set and $cnt must not be set for historic data.');
541557
}
542-
$url = $this->buildUVIndexUrl($lat, $lon, $dateTime, $timePrecision);
543558

559+
$url = $this->buildUVIndexUrl($mode, $lat, $lon, $cnt, $start, $end);
544560
return $this->cacheOrFetchResult($url);
545561
}
546562

@@ -575,10 +591,12 @@ private function cacheOrFetchResult($url)
575591
/** @var AbstractCache $cache */
576592
$cache = $this->cache;
577593
$cache->setSeconds($this->seconds);
594+
578595
if ($cache->isCached($url)) {
579596
$this->wasCached = true;
580597
return $cache->getCached($url);
581598
}
599+
582600
$result = $this->fetcher->fetch($url);
583601
$cache->setCached($url, $result);
584602
} else {
@@ -612,47 +630,41 @@ private function buildUrl($query, $units, $lang, $appid, $mode, $url)
612630
}
613631

614632
/**
615-
* @param float $lat
616-
* @param float $lon
617-
* @param \DateTime|\DateTimeImmutable $dateTime
618-
* @param string $timePrecision
633+
* @param string $mode The type of requested data.
634+
* @param float $lat The location's latitude.
635+
* @param float $lon The location's longitude.
636+
* @param int $cnt Number of returned days.
637+
* @param \DateTime $start Starting point of time period.
638+
* @param \DateTime $end Final point of time period.
619639
*
620640
* @return string
621641
*/
622-
private function buildUVIndexUrl($lat, $lon, $dateTime = null, $timePrecision = null)
642+
private function buildUVIndexUrl($mode, $lat, $lon, $cnt = null, \DateTime $start = null, \DateTime $end = null)
623643
{
624-
if ($dateTime !== null) {
625-
$format = '\Z';
626-
switch ($timePrecision) {
627-
/** @noinspection PhpMissingBreakStatementInspection */
628-
case 'second':
629-
$format = ':s' . $format;
630-
/** @noinspection PhpMissingBreakStatementInspection */
631-
case 'minute':
632-
$format = ':i' . $format;
633-
/** @noinspection PhpMissingBreakStatementInspection */
634-
case 'hour':
635-
$format = '\TH' . $format;
636-
/** @noinspection PhpMissingBreakStatementInspection */
637-
case 'day':
638-
$format = '-d' . $format;
639-
/** @noinspection PhpMissingBreakStatementInspection */
640-
case 'month':
641-
$format = '-m' . $format;
642-
case 'year':
643-
$format = 'Y' . $format;
644-
break;
645-
default:
646-
throw new \InvalidArgumentException('$timePrecision is invalid.');
647-
}
648-
// OWM only accepts UTC timezones.
649-
$dateTime->setTimezone(new \DateTimeZone('UTC'));
650-
$dateTime = $dateTime->format($format);
651-
} else {
652-
$dateTime = 'current';
644+
$params = array(
645+
'appid' => $this->apiKey,
646+
'lat' => $lat,
647+
'lon' => $lon,
648+
);
649+
650+
switch ($mode) {
651+
case 'historic':
652+
$requestMode = '/history';
653+
$params['start'] = $start->format('U');
654+
$params['end'] = $end->format('U');
655+
break;
656+
case 'forecast':
657+
$requestMode = '/forecast';
658+
$params['cnt'] = $cnt;
659+
break;
660+
case 'current':
661+
$requestMode = '';
662+
break;
663+
default:
664+
throw new \InvalidArgumentException("Invalid mode $mode for uv index url");
653665
}
654666

655-
return sprintf($this->uvIndexUrl . '/%s,%s/%s.json?appid=%s', $lat, $lon, $dateTime, $this->apiKey);
667+
return sprintf($this->uvIndexUrl . '%s?%s', $requestMode, http_build_query($params));
656668
}
657669

658670
/**
@@ -718,7 +730,8 @@ private function parseJson($answer)
718730
{
719731
$json = json_decode($answer);
720732
if (json_last_error() !== JSON_ERROR_NONE) {
721-
throw new OWMException('OpenWeatherMap returned an invalid json object. JSON error was: ' . $this->json_last_error_msg());
733+
throw new OWMException('OpenWeatherMap returned an invalid json object. JSON error was: "' .
734+
$this->json_last_error_msg() . '". The retrieved json was: ' . $answer);
722735
}
723736
if (isset($json->message)) {
724737
throw new OWMException('An error occurred: '. $json->message);

Cmfcmf/OpenWeatherMap/UVIndex.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ class UVIndex
4949
public function __construct($data)
5050
{
5151
$utctz = new \DateTimeZone('UTC');
52-
$this->time = new \DateTime($data->time, $utctz);
53-
$this->location = new Location($data->location->latitude, $data->location->longitude);
54-
$this->uvIndex = (float)$data->data;
52+
$this->time = new \DateTime($data->date_iso, $utctz);
53+
$this->location = new Location($data->lat, $data->lon);
54+
$this->uvIndex = (float)$data->value;
5555
}
5656
}

Examples/UVIndex.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
/**
3+
* OpenWeatherMap-PHP-API — A php api to parse weather data from http://www.OpenWeatherMap.org .
4+
*
5+
* @license MIT
6+
*
7+
* Please see the LICENSE file distributed with this source code for further
8+
* information regarding copyright and licensing.
9+
*
10+
* Please visit the following links to read about the usage policies and the license of
11+
* OpenWeatherMap before using this class:
12+
*
13+
* @see http://www.OpenWeatherMap.org
14+
* @see http://www.OpenWeatherMap.org/terms
15+
* @see http://openweathermap.org/appid
16+
*/
17+
use Cmfcmf\OpenWeatherMap;
18+
use Cmfcmf\OpenWeatherMap\Exception as OWMException;
19+
20+
require_once __DIR__ . '/bootstrap.php';
21+
22+
$cli = false;
23+
$lf = '<br>';
24+
if (php_sapi_name() === 'cli') {
25+
$lf = "\n";
26+
$cli = true;
27+
}
28+
29+
// Language of data (try your own language here!):
30+
$lang = 'de';
31+
32+
// Units (can be 'metric' or 'imperial' [default]):
33+
$units = 'metric';
34+
35+
// Get OpenWeatherMap object. Don't use caching (take a look into Example_Cache.php to see how it works).
36+
$owm = new OpenWeatherMap();
37+
$owm->setApiKey($myApiKey);
38+
39+
// Example 1: Get current uv index in Berlin.
40+
$uvIndex = $owm->getCurrentUVIndex(52.520008, 13.404954);
41+
echo "EXAMPLE 1$lf";
42+
43+
echo "Current uv index: $uvIndex->uvIndex";
44+
echo $lf;
45+
46+
// Example 2: Get uv index forecast in Berlin.
47+
$forecast = $owm->getForecastUVIndex(52.520008, 13.404954);
48+
echo "EXAMPLE 2$lf";
49+
50+
foreach ($forecast as $day) {
51+
echo "{$day->time->format('r')} will have an uv index of: $day->uvIndex";
52+
echo $lf;
53+
}
54+
55+
56+
// Example 3: Get historic uv index in Berlin.
57+
$history = $owm->getHistoricUVIndex(52.520008, 13.404954, new DateTime('-4month'), new DateTime('-3month'));
58+
echo "EXAMPLE 3$lf";
59+
60+
foreach ($history as $day) {
61+
echo "{$day->time->format('r')} had an uv index of: $day->uvIndex";
62+
echo $lf;
63+
}

0 commit comments

Comments
 (0)