@@ -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 );
0 commit comments