├── .travis.yml
├── README.md
├── Yr
├── Forecast.php
├── Location.php
├── TextualForecast.php
├── WeatherStation.php
└── Yr.php
├── autoload.php
├── composer.json
├── examples
├── README.md
├── current_forecast.php
├── forecasts_in_range.php
├── hourly_forecasts.php
├── meta_info.php
├── periodic_forecasts.php
├── textual.php
└── weather_stations.php
├── phpunit.xml
├── scripts
├── download_symbols.php
└── symbols
│ └── dummy
├── test.php
└── tests
└── Yr
├── ForecastTest.php
├── LocationTest.php
├── TextualForecastTest.php
├── WeatherStationTest.php
└── YrTest.php
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | php:
3 | - 5.5
4 | - 5.4
5 | - 5.3
6 | - hhvm
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/eigan/yr-php-library)
2 |
3 | Yr.no PHP library
4 | ==================
5 | PHP library for the norwegian wheather service yr.no. Currently in use on a fairly large norwegian site.
6 |
7 | ### Status
8 | Please note that I am not adding more feature at this time (other than accepting pull requests). Consider using something like forecast.io which has lots more data.
9 |
10 | ### Requirements
11 | - PHP 5.3
12 |
13 | ## Installation
14 | #### With [composer](https://getcomposer.org/)
15 | composer require eigan/yr
16 | #### Without composer
17 | Clone, or [download the repo as zip](https://github.com/eigan/yr-php-library/archive/master.zip). Place it somewhere on your server. Then include the autoload.php file in your code.
18 |
19 | Remember to set `date.timezone = "Europe/Oslo"` in php.ini or whatever is your timezone.
20 |
21 | ## Changelog
22 | **09 march 2014**
23 | - ! Yr::create() now returns a Location object
24 | - ! removed getLocation, use getName(), getCountry(), getType() instead
25 | - ! Forecast methods will no longer return the array when specifying null as parameter. Try to use toArray() instead
26 | - Added autoload.php to make it easier to load classes if/when structure changes.
27 | - Added Forecast->toArray()
28 | - Added Location->toArray()
29 | - Added WeatherStations (observations)
30 | - Added TextualForecasts
31 | - Added Location->getForecastAt($time), get a forecast at a specific unixtime
32 | - Added tests. 98.15% code coverage (coverage cant hit when yr return HTTP 500)
33 | - More exceptions and error checks in all classes
34 | - phpdoc cleanup
35 |
36 | ## Examples
37 | These examples require you to already have included autoload.php (or using an autoloader)
38 |
39 | #### Current forecast
40 | ```php
41 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp");
42 |
43 | $forecast = $yr->getCurrentForecast();
44 | printf("Time: %s to %s\n", $forecast->getFrom()->format("H:i"), $forecast->getTo()->format("H:i"));
45 | printf("Temp: %s %s\n", $forecast->getTemperature(), $forecast->getTemperature('unit'));
46 | printf("Wind: %smps %s\n", $forecast->getWindSpeed(), $forecast->getWindDirection('name'));
47 | ```
48 | ```
49 | Time: 16:00 to 17:00
50 | Temp: 8 celsius
51 | Wind: 5.7mps South-southwest
52 | ```
53 |
54 | #### Forecasts tomorrow
55 | ```php
56 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp");
57 |
58 | foreach($yr->getPeriodicForecasts(strtotime("tomorrow"), strtotime("midnight second day") - 1/*sec*/) as $forecast) {
59 | printf("Time: %s, %s degrees\n", $forecast->getFrom()->format("H:i"), $forecast->getTemperature());
60 | }
61 | ```
62 | ```
63 | Time: 00:00, 5 degrees
64 | Time: 06:00, 2 degrees
65 | Time: 12:00, 8 degrees
66 | Time: 18:00, 7 degrees
67 | ```
68 |
69 | #### Hourly forecasts rest of the day
70 |
71 | ```php
72 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp");
73 |
74 | foreach($yr->getHourlyForecasts(strtotime("now"), strtotime("tomorrow") - 1/*sec*/) as $forecast) {
75 | printf("Time: %s, %s degrees\n", $forecast->getFrom()->format("H:i"), $forecast->getTemperature());
76 | }
77 | ```
78 | ```
79 | Time: 20:00: 5 degrees
80 | Time: 21:00: 4 degrees
81 | Time: 22:00: 3 degrees
82 | Time: 23:00: 3 degrees
83 | ```
84 |
85 | See more examples in [examples directory](https://github.com/eigan/yr-php-library/tree/master/examples).
86 |
87 | ## Documentation
88 | ### Yr
89 | ```php
90 | /**
91 | *
92 | * Please read the rules for using the yr api http://om.yr.no/verdata/vilkar/
93 | * This class will implement caching for you
94 | *
95 | * @see http://om.yr.no/verdata/free-weather-data/
96 | */
97 | class Yr {
98 |
99 | /**
100 | * This method builds the Yr object from the freely available Yr api
101 | *
102 | * Notice that you have to be very specific about the location. Use the same location as you will find
103 | * on the yr.no site. For instance:
104 | *
105 | * This is the URL for the town Sandefjord:
106 | * http://www.yr.no/place/Norway/Vestfold/Sandefjord/Sandefjord/
107 | * Which with this library would be:
108 | * Yr::create("Norway/Vestfold/Sandefjord/Sandefjord")
109 | *
110 | *
111 | * @todo Check data we are setting on the yr object (meta data, dates, etc)
112 | * @param String $location the location, like Norway/Vestfold/Sandefjord
113 | * @param String $cache_path where to store the cache
114 | * @param int $cache_life life of the cache
115 | * @param String $language language, norwegian or english
116 | * @return Yr\Location
117 | * @throws \RuntimeException if cache path is not writeable
118 | * @throws \RuntimeException if the location is not correct
119 | * @throws \InvalidArgumentException
120 | */
121 | public static function create($location, $cache_path, $cache_life = 10, $language = "english");
122 | }
123 | ```
124 |
125 | ### Location
126 | ```php
127 | class Location {
128 |
129 | /**
130 | * @return String
131 | */
132 | public function getName();
133 |
134 | /**
135 | * @return String
136 | */
137 | public function getType();
138 |
139 | /**
140 | * @return String
141 | */
142 | public function getCountry();
143 | /**
144 | * @return String
145 | */
146 | public function getTimezone();
147 |
148 | /**
149 | * @return array
150 | */
151 | public function getLatLong();
152 |
153 | /**
154 | * List of links to the yr.no frontend
155 | *
156 | * @return array
157 | */
158 | public function getLinks();
159 |
160 | /**
161 | * Returns the current forecast (using periodic)
162 | *
163 | * @return Forecast
164 | */
165 | public function getCurrentForecast();
166 |
167 | /**
168 | * Returns the upcoming forecasts as array of Forecast objects
169 | *
170 | * You can optionally specify $from and $to as unixtime.
171 | *
172 | * @param int $from unixtime for when the first forecast should start
173 | * @param int $to unixtime for when the last forecast should start
174 | * @return array Forecast objects
175 | */
176 | public function getHourlyForecasts($from = null, $to = null);
177 |
178 | /**
179 | * There is 4 peridos in a day. You can check the Forecast::getPeriod()
180 | *
181 | * You can optionally specify $from and $to as unixtime.
182 | *
183 | * @param int $from unixtime for when the first forecast should start
184 | * @param int $to unixtime for when the last forecast should start
185 | * @return array Forecast objects
186 | */
187 | public function getPeriodicForecasts($from = null, $to = null);
188 |
189 | /**
190 | * Get a Forecast at a specific time
191 | *
192 | * @param String $time unixtime for when the forecast should be
193 | * @return Forecast[]
194 | */
195 | public function getForecastAt($time);
196 |
197 | /**
198 | * Note: Th textual forecasts is always norwegian..
199 | * @return TextualForecast[]
200 | */
201 | public function getTextualForecasts();
202 |
203 | /**
204 | * @return WeatherStation[]
205 | */
206 | public function getWeatherStations();
207 |
208 | /**
209 | * @return \Datetime
210 | */
211 | public function getSunrise();
212 |
213 | /**
214 | * @return \Datetime
215 | */
216 | public function getSunset();
217 | /**
218 | * Returns the time the hourly data was last updated
219 | * @return \DateTime
220 | */
221 | public function getLastUpdated();
222 |
223 | /**
224 | * Returns the time this will update next time the hourly data will update
225 | * @return \DateTime
226 | */
227 | public function getNextUpdate();
228 | /**
229 | * @return String
230 | */
231 | public function getCreditUrl();
232 |
233 | /**
234 | * You have to display this text with a link to the creditUrl! Read rules
235 | * @see getCreditUrl()
236 | * @return String
237 | */
238 | public function getCreditText()
239 | {
240 | return $this->credit_text;
241 | }
242 |
243 | /**
244 | * @return array
245 | */
246 | public function toArray();
247 | }
248 | ```
249 |
250 | ### Forecast
251 | ```php
252 | /**
253 | * Representing a forecast for the yr service
254 | *
255 | */
256 | class Forecast {
257 |
258 | /**
259 | * The symbol have three attributes with value
260 | * number [default]
261 | * name
262 | * var
263 | *
264 | * Default value will give "number"
265 | *
266 | * @param String $key number|name|var
267 | * @return string|array default is name
268 | */
269 | public function getSymbol($key = "name");
270 |
271 | /**
272 | * The symbol can have three attributes with value
273 | * value [default]
274 | * minvalue
275 | * maxvalue
276 | *
277 | * Default value will give "value"
278 | *
279 | * @param String $key value|minvalue|maxvalue
280 | * @return string
281 | */
282 | public function getPrecipitation($key = "value");
283 |
284 |
285 | /**
286 | * The wind direction have three attributes with value
287 | * deg
288 | * code [default]
289 | * name
290 | *
291 | * Default value will send the code
292 | *
293 | * @param String $key deg|code|name
294 | * @return string|array default is code
295 | */
296 | public function getWindDirection($key = "code");
297 |
298 |
299 | /**
300 | * The wind speed have two attributes with value
301 | * mps [default]
302 | * name
303 | *
304 | * @param String $key mps|name
305 | * @return string|array default value is meters pr sec
306 | */
307 | public function getWindSpeed($key = "mps");
308 |
309 | /**
310 | * Utility method to get the filename for the arrows (speed and direction)
311 | *
312 | * http://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.{$speed}.{$degree}.png
313 | *
314 | * So you can use the icon like so:
315 | * http://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.{$forecast->getWindIconKey()}.png
316 | *
317 | * if it returns 0, then it should be "vindstille" (no wind) http://fil.nrk.no/yr/grafikk/vindpiler/32/vindstille.png
318 | *
319 | * @returm string
320 | */
321 | public function getWindIconKey();
322 |
323 | /**
324 | * The temperatur have two attributes with value
325 | * unit
326 | * value [default]
327 | *
328 | * @param String $key value|unit
329 | * @return string|array see documentation
330 | */
331 | public function getTemperature($key = "value");
332 |
333 | /**
334 | * The pressure have two attributes with value
335 | * unit
336 | * value [default]
337 | *
338 | * @param String $key value|unit
339 | * @return string|array see documentation
340 | */
341 | public function getPressure($key = "value");
342 |
343 |
344 | /**
345 | * Time from when the forecast begins
346 | * @return \DateTime
347 | */
348 | public function getFrom();
349 |
350 | /**
351 | * Time for when the forecast ends
352 | * @return \DateTime
353 | */
354 | public function getTo();
355 |
356 | /**
357 | * Period of the day. This might be null in hourly
358 | * @return int|null
359 | */
360 | public function getPeriod();
361 |
362 | /**
363 | * @return array
364 | */
365 | public function toArray();
366 | }
367 | ```
368 |
369 | ### TextualForecast
370 | ```php
371 | /**
372 | * Textual forecasts for a given day (or two days)
373 | * Note: There is some html inside the getText()...
374 | *
375 | */
376 | class TextualForecast {
377 |
378 | /**
379 | * @return String
380 | */
381 | public function getTitle();
382 |
383 | /**
384 | * @return String
385 | */
386 | public function getText();
387 |
388 | /**
389 | * @return \Datetime
390 | */
391 | public function getFrom();
392 |
393 | /**
394 | * @return \DateTime
395 | */
396 | public function getTo();
397 | }
398 | ```
399 |
400 | ### WeatherStation
401 | ```php
402 | /**
403 | * Weather Station
404 | * Note that the Forecast object will not be complete since all data from it might not be set :/
405 | *
406 | */
407 | class WeatherStation {
408 |
409 | /**
410 | * @return String
411 | */
412 | public function getName();
413 |
414 | /**
415 | * @return numeric
416 | */
417 | public function getDistance();
418 |
419 | /**
420 | * array('lat' => '[xx.xxxx]', 'long' => '[xx.xxxx]')
421 | *
422 | * @return array
423 | */
424 | public function getLatLong();
425 |
426 | /**
427 | *
428 | * @return String
429 | */
430 | public function getSource();
431 |
432 | /**
433 | * Warning: Not everything will be set on this object
434 | *
435 | * @return Forecast the current forecast reported by this weatherstation
436 | */
437 | public function getForecast();
438 |
439 | /**
440 | * @return array
441 | */
442 | public function toArray();
443 | }
444 | ```
445 |
446 | ## License
447 | MIT http://www.tldrlegal.com/license/mit-license
448 |
--------------------------------------------------------------------------------
/Yr/Forecast.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class Forecast
12 | {
13 | /**
14 | * From datetime.
15 | *
16 | * @var \DateTime
17 | */
18 | public $from;
19 |
20 | /**
21 | * To datetime.
22 | *
23 | * @var \DateTime
24 | */
25 | public $to;
26 |
27 | /**
28 | * Period of the date, will be a number from 0 to 4
29 | * where 0 is early in the morning and 4 is at night.
30 | *
31 | * @var int
32 | */
33 | public $period;
34 |
35 | /**
36 | * Typically the icon to display.
37 | *
38 | * @var array
39 | */
40 | public $symbol;
41 |
42 | /**
43 | * Precipitation in millimeters.
44 | *
45 | * @var String
46 | */
47 | public $precipitation;
48 |
49 | /**
50 | * Data for wind direction.
51 | *
52 | * @var array
53 | */
54 | public $wind_direction;
55 |
56 | /**
57 | * Data for wind speed.
58 | *
59 | * @var array
60 | */
61 | public $wind_speed;
62 |
63 | /**
64 | * Data for temperature.
65 | *
66 | * @var array
67 | */
68 | public $temperature;
69 |
70 | /**
71 | * Data for pressure.
72 | *
73 | * @var array
74 | */
75 | public $pressure;
76 |
77 | /**
78 | * We do NOTHING.
79 | */
80 | public function __construct()
81 | {
82 | }
83 |
84 | /**
85 | * Creates from simplexml object.
86 | *
87 | * @param \SimpleXMLElement $xml The xml node element
88 | *
89 | * @return Forecast
90 | *
91 | * @throws \RuntimeException If some data is missing for xml
92 | */
93 | public static function getForecastFromXml(\SimpleXMLElement $xml)
94 | {
95 | $forecast = new Forecast();
96 |
97 | $data = Yr::xmlToArray($xml);
98 |
99 | if (!isset($data['from'], $data['to'])) {
100 | throw new \RuntimeException("Missing from/to for forecast");
101 | }
102 |
103 | $forecast->from = \DateTime::createFromFormat(Yr::XML_DATE_FORMAT, $data['from']);
104 | $forecast->to = \DateTime::createFromFormat(Yr::XML_DATE_FORMAT, $data['to']);
105 | $forecast->period = isset($data['period']) ? $data['period'] : "";
106 |
107 | if (!isset($data['symbol'],
108 | $data['precipitation'],
109 | $data['windDirection'],
110 | $data['windSpeed'],
111 | $data['temperature'],
112 | $data['pressure'])) {
113 | throw new \RuntimeException("Missing data for forecast");
114 | }
115 |
116 | $forecast->symbol = $data['symbol'];
117 | $forecast->precipitation = $data['precipitation'];
118 | $forecast->wind_direction = $data['windDirection'];
119 | $forecast->wind_speed = $data['windSpeed'];
120 | $forecast->temperature = $data['temperature'];
121 | $forecast->pressure = $data['pressure'];
122 |
123 | return $forecast;
124 | }
125 |
126 | /**
127 | * The symbol have four attributes with value
128 | * number
129 | * numberEx
130 | * name [default]
131 | * var.
132 | *
133 | * Default value will give "name"
134 | *
135 | * @param String $key number|name|var
136 | *
137 | * @return string|array default is name
138 | */
139 | public function getSymbol($key = "name")
140 | {
141 | return isset($this->symbol[$key]) ? $this->symbol[$key] : null;
142 | }
143 |
144 | /**
145 | * @param array $symbol
146 | */
147 | public function setSymbol($symbol)
148 | {
149 | $this->symbol = $symbol;
150 | }
151 |
152 | /**
153 | * The symbol can have three attributes with value
154 | * value [default]
155 | * minvalue
156 | * maxvalue.
157 | *
158 | * Default value will give "value"
159 | *
160 | * @param String $key value|minvalue|maxvalue
161 | *
162 | * @return string
163 | */
164 | public function getPrecipitation($key = "value")
165 | {
166 | return isset($this->precipitation[$key]) ? $this->precipitation[$key] : null;
167 | }
168 |
169 | /**
170 | * @param String $precipitation
171 | */
172 | public function setPrecipitation($precipitation)
173 | {
174 | $this->precipitation = $precipitation;
175 | }
176 |
177 | /**
178 | * The wind direction have three attributes with value
179 | * deg
180 | * code [default]
181 | * name.
182 | *
183 | * Default value will send the code
184 | *
185 | * @param String $key deg|code|name
186 | *
187 | * @return string|array default is code
188 | */
189 | public function getWindDirection($key = "code")
190 | {
191 | return isset($this->wind_direction[$key]) ? $this->wind_direction[$key] : null;
192 | }
193 |
194 | /**
195 | * @param array $wind_direction
196 | */
197 | public function setWindDirection($wind_direction)
198 | {
199 | $this->wind_direction = $wind_direction;
200 | }
201 |
202 | /**
203 | * The wind speed have two attributes with value
204 | * mps [default]
205 | * name.
206 | *
207 | * @param String $key mps|name
208 | *
209 | * @return string|array default value is meters pr sec
210 | */
211 | public function getWindSpeed($key = "mps")
212 | {
213 | return isset($this->wind_speed[$key]) ? $this->wind_speed[$key] : null;
214 | }
215 |
216 | /**
217 | * @param array $wind_speed
218 | */
219 | public function setWindSpeed($wind_speed)
220 | {
221 | $this->wind_speed = $wind_speed;
222 | }
223 |
224 | /**
225 | * Utility method to get the filename for the arrows (speed and direction).
226 | *
227 | * http://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.{$speed}.{$degree}.png
228 | *
229 | * So you can use the icon like so:
230 | * http://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.{$forecast->getWindIconKey()}.png
231 | *
232 | * if it returns 0, then it should be "vindstille" (no wind) http://fil.nrk.no/yr/grafikk/vindpiler/32/vindstille.png
233 | *
234 | * @returm string
235 | */
236 | public function getWindIconKey()
237 | {
238 | $speed = (round(($this->getWindSpeed("mps")/2.5)) * 2.5) * 10;
239 | $speed = str_pad($speed, 4, '0', STR_PAD_LEFT);
240 |
241 | // 2 and down is 0 speed - vindstille
242 | if ($this->getWindSpeed() <= 0.2) {
243 | return 0;
244 | }
245 |
246 | $degree = round((($this->getWindDirection("deg")/10) * 2) / 2) * 10;
247 | $degree = str_pad($degree, 3, '0', STR_PAD_LEFT);
248 |
249 | // 360 degree is 0
250 | if ($degree >= 360) {
251 | $degree = 0;
252 | }
253 |
254 | return "$speed.$degree";
255 | }
256 |
257 | /**
258 | * The temperatur have two attributes with value
259 | * unit
260 | * value [default].
261 | *
262 | * @param String $key value|unit
263 | *
264 | * @return string|array see documentation
265 | */
266 | public function getTemperature($key = "value")
267 | {
268 | return isset($this->temperature[$key]) ? $this->temperature[$key] : null;
269 | }
270 |
271 | /**
272 | * @param array $temperature
273 | */
274 | public function setTemperature($temperature)
275 | {
276 | $this->temperature = $temperature;
277 | }
278 |
279 | /**
280 | * The pressure have two attributes with value
281 | * unit
282 | * value [default].
283 | *
284 | * @param String $key value|unit
285 | *
286 | * @return string|array see documentation
287 | */
288 | public function getPressure($key = "value")
289 | {
290 | return isset($this->pressure[$key]) ? $this->pressure[$key] : null;
291 | }
292 |
293 | /**
294 | * @param array $pressure
295 | */
296 | public function setPressure($pressure)
297 | {
298 | $this->pressure = $pressure;
299 | }
300 |
301 | /**
302 | * Time from when the forecast begins.
303 | *
304 | * @return \DateTime
305 | */
306 | public function getFrom()
307 | {
308 | return $this->from;
309 | }
310 |
311 | /**
312 | * @param \DateTime $from
313 | */
314 | public function setFrom(\DateTime $from)
315 | {
316 | $this->from = $from;
317 | }
318 |
319 | /**
320 | * Time for when the forecast ends.
321 | *
322 | * @return \DateTime
323 | */
324 | public function getTo()
325 | {
326 | return $this->to;
327 | }
328 |
329 | /**
330 | * @param \DateTime $to
331 | */
332 | public function setTo(\DateTime $to)
333 | {
334 | $this->to = $to;
335 | }
336 |
337 | /**
338 | * Period of the day. This might be null in hourly.
339 | *
340 | * @return int|null
341 | */
342 | public function getPeriod()
343 | {
344 | return strlen($this->period) > 0 ? $this->period : null;
345 | }
346 |
347 | /**
348 | * @param int $period
349 | */
350 | public function setPeriod($period)
351 | {
352 | $this->period = $period;
353 | }
354 |
355 | /**
356 | * @return array
357 | */
358 | public function toArray()
359 | {
360 | return array(
361 | 'from' => $this->getFrom(),
362 | 'to' => $this->getTo(),
363 | 'symbol' => $this->symbol,
364 | 'temperature' => $this->temperature,
365 | 'wind_speed' => $this->wind_speed,
366 | 'wind_direction' => $this->wind_direction,
367 | 'period' => $this->period,
368 | );
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/Yr/Location.php:
--------------------------------------------------------------------------------
1 | location = $location;
84 | $this->forecasts_periodic = $forecasts_periodic;
85 | $this->forecasts_hourly = $forecasts_hourly;
86 | $this->links = array();
87 | $this->weather_stations = array();
88 | }
89 |
90 | /**
91 | * @return String
92 | */
93 | public function getName()
94 | {
95 | return $this->location['name'];
96 | }
97 |
98 | /**
99 | * @return String
100 | */
101 | public function getType()
102 | {
103 | return $this->location['type'];
104 | }
105 |
106 | /**
107 | * @return String
108 | */
109 | public function getCountry()
110 | {
111 | return $this->location['country'];
112 | }
113 |
114 | /**
115 | * @return String
116 | */
117 | public function getTimezone()
118 | {
119 | return $this->location['timezone']['id'];
120 | }
121 |
122 | /**
123 | * @return array
124 | */
125 | public function getLatLong()
126 | {
127 | return array(
128 | 'lat' => $this->location['location']['latitude'],
129 | 'long' => $this->location['location']['longitude'],
130 | );
131 | }
132 |
133 | /**
134 | * List of links to the yr.no frontend
135 | *
136 | * @return array
137 | */
138 | public function getLinks()
139 | {
140 | return $this->links;
141 | }
142 |
143 | /**
144 | * Adds a link
145 | *
146 | * @param String $name
147 | * @param String $url
148 | */
149 | public function addLink($name, $url)
150 | {
151 | $this->links[$name] = $url;
152 | }
153 |
154 | /**
155 | * Returns the current forecast (using periodic)
156 | *
157 | * @return Forecast
158 | */
159 | public function getCurrentForecast()
160 | {
161 | $forecast = reset($this->forecasts_hourly);
162 |
163 | return $forecast instanceof Forecast ? $forecast : null;
164 | }
165 |
166 | /**
167 | * Returns the upcoming forecasts as array of Forecast objects
168 | *
169 | * You can optionally specify $from and $to as unixtime.
170 | *
171 | * @param int $from unixtime for when the first forecast should start
172 | * @param int $to unixtime for when the last forecast should start
173 | * @return array Forecast objects
174 | */
175 | public function getHourlyForecasts($from = null, $to = null)
176 | {
177 | if (!is_null($from) || !is_null($to)) {
178 | return $this->getForecastsBetweenTime($this->forecasts_hourly, $from, $to);
179 | }
180 |
181 | return $this->forecasts_hourly;
182 | }
183 |
184 | /**
185 | * There is 4 peridos in a day. You can check the Forecast::getPeriod()
186 | *
187 | * You can optionally specify $from and $to as unixtime.
188 | *
189 | * @param int $from unixtime for when the first forecast should start
190 | * @param int $to unixtime for when the last forecast should start
191 | * @return array Forecast objects
192 | */
193 | public function getPeriodicForecasts($from = null, $to = null)
194 | {
195 | if (!is_null($from) || !is_null($to)) {
196 | return $this->getForecastsBetweenTime($this->forecasts_periodic, $from, $to);
197 | }
198 |
199 | return $this->forecasts_periodic;
200 | }
201 |
202 | /**
203 | * Get a Forecast at a specific time
204 | *
205 | * @param String $time unixtime for when the forecast should be
206 | * @return Forecast[]
207 | */
208 | public function getForecastAt($time)
209 | {
210 | $forecasts = $this->getForecastsBetweenTime($this->forecasts_hourly, $time);
211 |
212 | return reset($forecasts);
213 | }
214 |
215 | /**
216 | * Internal function to find forecasts between a given time
217 | *
218 | * Notice that if $from is null, we change it to now()
219 | * and if $to is null, we change it to the time one year from now
220 | *
221 | * @param Forecast[] $forecasts the list of forecasts to check
222 | * @param int $from unixtime for when the forecast should start
223 | * @param int $to unixtime for when the last forecast should start
224 | * @return array list of matching forecasts
225 | */
226 | protected function getForecastsBetweenTime($forecasts, $from, $to = null)
227 | {
228 | $result = array();
229 |
230 | // Check for null, or non valid unixtimes
231 | $from = is_null($from) || !is_int($from) ? time() : $from;
232 | $to = is_null($to) || !is_int($to) ? strtotime("1 year") : $to;
233 |
234 | foreach ($forecasts as $forecast) {
235 | if ($forecast->getFrom()->getTimestamp() >= $from &&
236 | $forecast->getFrom()->getTimestamp() <= $to) {
237 | $result[] = $forecast;
238 | }
239 | }
240 |
241 | return $result;
242 | }
243 |
244 | /**
245 | * Note: The textual forecasts is always norwegian..
246 | * Note: Places outside of Norway might not have textual forecasts
247 | *
248 | * @return TextualForecast[]
249 | */
250 | public function getTextualForecasts()
251 | {
252 | return $this->textual_forecasts;
253 | }
254 |
255 | /**
256 | * @param TextualForecast[] $forecasts
257 | */
258 | public function setTextualForecasts(array $forecasts)
259 | {
260 | $this->textual_forecasts = $forecasts;
261 | }
262 |
263 | /**
264 | * Note: Places outside of Norway might not have weather stations
265 | *
266 | * @return WeatherStation[]
267 | */
268 | public function getWeatherStations()
269 | {
270 | return $this->weather_stations;
271 | }
272 |
273 | /**
274 | * @param WeatherStation[] $weather_stations
275 | */
276 | public function setWeatherStations($weather_stations)
277 | {
278 | $this->weather_stations = $weather_stations;
279 | }
280 |
281 | /**
282 | * @return \Datetime
283 | */
284 | public function getSunrise()
285 | {
286 | return $this->sunrise;
287 | }
288 |
289 | /**
290 | * @param \Datetime
291 | */
292 | public function setSunrise(\Datetime $time)
293 | {
294 | $this->sunrise = $time;
295 | }
296 |
297 | /**
298 | * @return \Datetime
299 | */
300 | public function getSunset()
301 | {
302 | return $this->sunset;
303 | }
304 |
305 | /**
306 | * @param \Datetime $time
307 | */
308 | public function setSunset(\Datetime $time)
309 | {
310 | $this->sunset = $time;
311 | }
312 |
313 | /**
314 | * Returns the time the hourly data was last updated
315 | * @return \DateTime
316 | */
317 | public function getLastUpdated()
318 | {
319 | return $this->last_update_date;
320 | }
321 |
322 | /**
323 | * Setter for last update
324 | * @param \DateTime $date
325 | */
326 | public function setLastUpdated(\Datetime $date)
327 | {
328 | $this->last_update_date = $date;
329 | }
330 |
331 | /**
332 | * Returns the time this will update next time the hourly data will update
333 | * @return \DateTime
334 | */
335 | public function getNextUpdate()
336 | {
337 | return $this->next_update_date;
338 | }
339 |
340 | /**
341 | *
342 | * @param \DateTime
343 | */
344 | public function setNextUpdate(\Datetime $date)
345 | {
346 | $this->next_update_date = $date;
347 | }
348 |
349 | /**
350 | * @return String
351 | */
352 | public function getCreditUrl()
353 | {
354 | return $this->credit_url;
355 | }
356 |
357 | /**
358 | * @param String $url
359 | */
360 | public function setCreditUrl($url)
361 | {
362 | $this->credit_url = $url;
363 | }
364 |
365 | /**
366 | * You have to display this text with a link to the creditUrl! Read rules
367 | * @see getCreditUrl()
368 | * @return String
369 | */
370 | public function getCreditText()
371 | {
372 | return $this->credit_text;
373 | }
374 |
375 | /**
376 | * @param String $text
377 | */
378 | public function setCreditText($text)
379 | {
380 | $this->credit_text = $text;
381 | }
382 |
383 | /**
384 | * @return array
385 | */
386 | public function toArray()
387 | {
388 | return array(
389 | 'location' => $this->location,
390 | 'links' => $this->links,
391 | 'last_update' => $this->getLastUpdated(),
392 | 'next_update' => $this->getNextUpdate(),
393 | 'credit_text' => $this->getCreditText(),
394 | 'credit_url' => $this->getCreditUrl(),
395 | 'sunrise' => $this->getSunrise(),
396 | 'sunset' => $this->getSunset(),
397 | 'forecasts' => $this->getHourlyForecasts(),
398 | 'weather_stations' => $this->getWeatherStations(),
399 | );
400 | }
401 | }
402 |
--------------------------------------------------------------------------------
/Yr/TextualForecast.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class TextualForecast
14 | {
15 | /**
16 | * @var String
17 | */
18 | protected $title;
19 |
20 | /**
21 | * @var String
22 | */
23 | protected $text;
24 |
25 | /**
26 | * @var \Datetime
27 | */
28 | protected $from;
29 |
30 | /**
31 | * @var \Datetime
32 | */
33 | protected $to;
34 |
35 | /**
36 | * @var String
37 | */
38 | const XML_DATE_FORMAT = "Y-m-d";
39 |
40 | /**
41 | * @param String $title
42 | * @param String $text
43 | * @param \DateTime $from
44 | * @param \DateTime $to
45 | * @throws \InvalidArgumentException
46 | */
47 | public function __construct($title, $text, \DateTime $from, \DateTime $to = null)
48 | {
49 | if (empty($title) || empty($text)) {
50 | throw new \InvalidArgumentException("Title/or text is empty");
51 | }
52 |
53 | $this->title = $title;
54 | $this->text = $text;
55 | $this->from = $from;
56 | $this->to = $to === null ? $from : $to;
57 | }
58 |
59 | /**
60 | * @param \SimpleXMLElement $xml
61 | * @return TextualForecast
62 | * @throws \InvalidArgumentException
63 | */
64 | public static function createTextualForecastFromXml(\SimpleXMLElement $xml)
65 | {
66 | $data = Yr::xmlToArray($xml);
67 |
68 | $title = $data['title'];
69 | $text = $data['body'];
70 | $from = \DateTime::createFromFormat(TextualForecast::XML_DATE_FORMAT, $data['from']);
71 | $to = \DateTime::createFromFormat(TextualForecast::XML_DATE_FORMAT, $data['to']);
72 |
73 | return new TextualForecast($title, $text, $from, $to);
74 | }
75 |
76 | /**
77 | * @return String
78 | */
79 | public function getTitle()
80 | {
81 | return $this->title;
82 | }
83 |
84 | /**
85 | * @return String
86 | */
87 | public function getText()
88 | {
89 | return $this->text;
90 | }
91 |
92 | /**
93 | * @return \Datetime
94 | */
95 | public function getFrom()
96 | {
97 | return $this->from;
98 | }
99 |
100 | /**
101 | * @return \DateTime
102 | */
103 | public function getTo()
104 | {
105 | return $this->to;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Yr/WeatherStation.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | class WeatherStation
13 | {
14 | /**
15 | * @var String
16 | */
17 | protected $name;
18 |
19 | /**
20 | * @var int
21 | */
22 | protected $distance;
23 |
24 | /**
25 | * @var array
26 | */
27 | protected $latLong;
28 |
29 | /**
30 | * @var String
31 | */
32 | protected $source;
33 |
34 | /**
35 | * @var Forecast
36 | */
37 | protected $forecast;
38 |
39 | /**
40 | * @param $name
41 | * @param $distance
42 | * @param array $latLong
43 | * @param $source
44 | */
45 | public function __construct($name, $distance, array $latLong, $source)
46 | {
47 | $this->name = $name;
48 | $this->distance = (int) $distance;
49 | $this->latLong = $latLong;
50 | $this->source = $source;
51 |
52 | $this->forecast = new Forecast();
53 | }
54 |
55 | /**
56 | * @param \SimpleXMLElement $xml
57 | * @return WeatherStation
58 | */
59 | public static function getWeatherStationFromXml(\SimpleXMLElement $xml)
60 | {
61 | $data = Yr::xmlToArray($xml);
62 |
63 | $name = $data['name'];
64 | $distance = $data['distance'];
65 | $latLong = array('lat' => $data['lat'], 'long' => $data['lon']);
66 | $source = $data['source'];
67 |
68 | $station = new WeatherStation($name, $distance, $latLong, $source);
69 |
70 | $forecast = $station->getForecast();
71 |
72 | if (isset($data['symbol'])) {
73 | $forecast->setSymbol($data['symbol']);
74 | }
75 |
76 | if (isset($data['temperature'])) {
77 | $forecast->setTemperature($data['temperature']);
78 | }
79 |
80 | if (isset($data['windDirection'])) {
81 | $forecast->setWindDirection($data['windDirection']);
82 | }
83 |
84 | if (isset($data['windSpeed'])) {
85 | $forecast->setWindSpeed($data['windSpeed']);
86 | }
87 |
88 | return $station;
89 | }
90 |
91 | /**
92 | * @return String
93 | */
94 | public function getName()
95 | {
96 | return $this->name;
97 | }
98 |
99 | /**
100 | * @return int
101 | */
102 | public function getDistance()
103 | {
104 | return $this->distance;
105 | }
106 |
107 | /**
108 | * array('lat' => '[xx.xxxx]', 'long' => '[xx.xxxx]')
109 | *
110 | * @return array
111 | */
112 | public function getLatLong()
113 | {
114 | return $this->latLong;
115 | }
116 |
117 | /**
118 | *
119 | * @return String
120 | */
121 | public function getSource()
122 | {
123 | return $this->source;
124 | }
125 |
126 | /**
127 | * Warning: Not everything will be set on this object
128 | *
129 | * @return Forecast the current forecast reported by this weatherstation
130 | */
131 | public function getForecast()
132 | {
133 | return $this->forecast;
134 | }
135 |
136 | /**
137 | * @param Forecast $forecast
138 | */
139 | public function setForecast(Forecast $forecast)
140 | {
141 | $this->forecast = $forecast;
142 | }
143 |
144 | /**
145 | * @return array
146 | */
147 | public function toArray()
148 | {
149 | return array(
150 | 'name' => $this->name,
151 | 'distance' => $this->distance,
152 | 'latLong' => $this->latLong,
153 | 'source' => $this->source,
154 | 'forecast' => $this->forecast,
155 | );
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/Yr/Yr.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class Yr
14 | {
15 | /**
16 | * This is the format used in the xml files.
17 | * It is converted to DateTime everywhere.
18 | *
19 | * @var string
20 | */
21 | const XML_DATE_FORMAT = "Y-m-d?H:i:s";
22 |
23 | /**
24 | * Yr url.
25 | */
26 | const API_URL = "http://www.yr.no/";
27 |
28 | /**
29 | * HTTP 200 response with text/xml.
30 | */
31 | const SERVICE_OK = 1;
32 |
33 | /**
34 | * HTTP 200 with text/html, or HTTP 404.
35 | */
36 | const SERVICE_LOCATION_INVALID = 5;
37 |
38 | /**
39 | * HTTP 500, or no response.
40 | */
41 | const SERVICE_UNKNOWN_STATE = 10;
42 |
43 | /**
44 | * Prefix for the xml files.
45 | */
46 | const CACHE_PREFIX = "phpyrno_";
47 |
48 | /**
49 | * Only static functions here.
50 | */
51 | protected function __construct()
52 | {
53 | }
54 |
55 | /**
56 | * This method downloads and builds the Yr object from the freely available Yr api.
57 | *
58 | * Notice that you have to be very specific about the location.
59 | * Use the same location as you will find on the yr.no site. For instance:
60 | *
61 | * This is the URL for the town Sandefjord:
62 | * http://www.yr.no/place/Norway/Vestfold/Sandefjord/Sandefjord/
63 | * Which with this library would be:
64 | * Yr::create("Norway/Vestfold/Sandefjord/Sandefjord")
65 | *
66 | * @param String $location the location, like Norway/Vestfold/Sandefjord
67 | * @param String $cache_path where to store the cache
68 | * @param int $cache_life life of the cache in minutes
69 | * @param String $language language, norwegian or english
70 | *
71 | * @return Location
72 | *
73 | * @throws \RuntimeException if cache path is not writeable
74 | * @throws \RuntimeException if the location is not correct
75 | * @throws \InvalidArgumentException
76 | *
77 | * @todo Check data we are setting on the yr object (meta data, dates, etc)
78 | */
79 | public static function create(
80 | $location,
81 | $cache_path,
82 | $cache_life = 10,
83 | $language = "english"
84 | ) {
85 | if (!isset($location) || empty($location)) {
86 | throw new \InvalidArgumentException("Location need to be set");
87 | }
88 |
89 | if (!isset($cache_path) || empty($cache_path)) {
90 | throw new \InvalidArgumentException("Cache path need to be set");
91 | }
92 |
93 | // Get url, it is different for each language
94 | $baseurl = self::getApiUrlByLanguage($language);
95 |
96 | // Clean the cache path
97 | $cache_path = realpath($cache_path).DIRECTORY_SEPARATOR;
98 |
99 | // Convert cache life to seconds
100 | $cache_life_sec = $cache_life * 60;
101 |
102 | // Check if cache path is readable
103 | if (!is_writable($cache_path)) {
104 | throw new \RuntimeException("Cache path ($cache_path) is not writable");
105 | }
106 |
107 | // Cache paths for the xml data
108 | $cachename = self::CACHE_PREFIX.md5($baseurl.$location);
109 | $xml_periodic_path = $cache_path.$cachename."_periodic.xml";
110 | $xml_hourly_path = $cache_path.$cachename."_hourly.xml";
111 |
112 | // Check response from web service
113 | // This is a critical process if we have no cache.
114 | // Please see Yr::getUrlResponseCode() for explanation
115 | if (!is_readable($xml_periodic_path) || !is_readable($xml_hourly_path)) {
116 | $test = self::getServiceResponseCode($baseurl.$location);
117 |
118 | if ($test == self::SERVICE_LOCATION_INVALID) {
119 | throw new \RuntimeException(
120 | "The location ($location) is wrong.
121 | Please check Yr::create() documentation."
122 | );
123 | } elseif ($test == self::SERVICE_UNKNOWN_STATE) {
124 | throw new \RuntimeException(
125 | "Could not connect to yr service.
126 | Tried the url for 7 times, but did not work.
127 | Might be do to invalid location, or yr service is down."
128 | );
129 | }
130 | }
131 |
132 | // Download the periodic xml if we don't have it
133 | $xml_periodic = self::downloadData(
134 | "$baseurl/$location/forecast.xml",
135 | $xml_periodic_path,
136 | $cache_life_sec
137 | );
138 |
139 | // Download the hourly xml if we don't have it
140 | $xml_hourly = self::downloadData(
141 | "$baseurl/$location/forecast_hour_by_hour.xml",
142 | $xml_hourly_path,
143 | $cache_life_sec
144 | );
145 |
146 | return self::createFromXML($xml_periodic, $xml_hourly);
147 | }
148 |
149 | /**
150 | * Build the Yr object
151 | *
152 | * @param String $periodic XML file content
153 | * @param String $hourly XML file content
154 | *
155 | * @return Location
156 | *
157 | * @throws \InvalidArgumentException
158 | * @throws \RuntimeException
159 | */
160 | public static function createFromXML($periodic, $hourly)
161 | {
162 | if (!isset($periodic) || empty($periodic)) {
163 | throw new \InvalidArgumentException("Periodic XML document need to be set");
164 | }
165 |
166 | if (!isset($hourly) || empty($hourly)) {
167 | throw new \InvalidArgumentException("Hourly XML document need to be set");
168 | }
169 |
170 | $xml_hourly = new \SimpleXMLElement($hourly);
171 | $xml_periodic = new \SimpleXMLElement($periodic);
172 |
173 | // Forecasts
174 | $forecasts_hourly = self::getForecastsFromXml($xml_hourly);
175 | $forecasts_periodic = self::getForecastsFromXml($xml_periodic);
176 |
177 | // Textual
178 | $textual_forecasts = self::getTextualForecastsFromXml($xml_hourly);
179 |
180 | // weather_stations
181 | $weather_stations = self::getWeatherStationsFromXml($xml_hourly);
182 |
183 | // Get other data for our object
184 | $location = self::xmlToArray($xml_periodic->location);
185 | $links = self::xmlToArray($xml_periodic->links);
186 | $credit = self::xmlToArray($xml_periodic->credit->link);
187 | $meta = self::xmlToArray($xml_periodic->meta);
188 | $sun = self::xmlToArray($xml_periodic->sun);
189 |
190 | // Set the data on the object
191 | try {
192 | $yr = new Location($location, $forecasts_periodic, $forecasts_hourly);
193 |
194 | $yr->setWeatherStations($weather_stations);
195 | $yr->setTextualForecasts($textual_forecasts);
196 |
197 | if (isset($links['link'])) {
198 | foreach ($links['link'] as $link) {
199 | $yr->addLink($link['id'], $link['url']);
200 | }
201 | }
202 |
203 | if (isset($credit['text'], $credit['url'])) {
204 | $yr->setCreditText($credit['text']);
205 | $yr->setCreditUrl($credit['url']);
206 | }
207 |
208 | $yr->setLastUpdated(
209 | \DateTime::createFromFormat(self::XML_DATE_FORMAT, $meta['lastupdate'])
210 | );
211 | $yr->setNextUpdate(
212 | \DateTime::createFromFormat(self::XML_DATE_FORMAT, $meta['nextupdate'])
213 | );
214 |
215 | if (isset($sun['set'], $sun['rise'])) {
216 | $yr->setSunset(\DateTime::createFromFormat(self::XML_DATE_FORMAT, $sun['set']));
217 | $yr->setSunrise(\DateTime::createFromFormat(self::XML_DATE_FORMAT, $sun['rise']));
218 | }
219 |
220 | // Finally return the object
221 | return $yr;
222 | } catch (\Exception $e) {
223 | // We fall back and send exception if something goes wrong
224 | throw new \RuntimeException("Could not create Location object. Message: " . $e->getMessage());
225 | }
226 | }
227 |
228 | /**
229 | * Converts xml to array and hide comments.
230 | *
231 | * @param array|\SimpleXMLElement $data xml data
232 | *
233 | * @return array
234 | */
235 | public static function xmlToArray($data)
236 | {
237 | $out = array();
238 |
239 | foreach ((array) $data as $index => $node) {
240 | if ($index == 'comment') {
241 | continue;
242 | }
243 |
244 | if (is_object($node) || is_array($node)) {
245 | $value = self::xmlToArray($node);
246 | } else {
247 | $value = (string) $node;
248 | }
249 |
250 | if ($index == '@attributes') {
251 | $out = array_merge($out, $value);
252 | } else {
253 | $out[$index] = $value;
254 | }
255 | }
256 |
257 | return $out;
258 | }
259 |
260 | /**
261 | * @param \SimpleXMLElement $xml
262 | *
263 | * @return WeatherStation[]
264 | */
265 | public static function getWeatherStationsFromXml(\SimpleXMLElement $xml)
266 | {
267 | $weather_stations = array();
268 | if (!empty($xml->observations)) {
269 | foreach ($xml->observations->weatherstation as $observation) {
270 | try {
271 | $weather_stations[] = WeatherStation::getWeatherStationFromXml($observation);
272 | } catch (\Exception $e) {
273 | // Skip those we cant create..
274 | }
275 | }
276 | }
277 |
278 | return $weather_stations;
279 | }
280 |
281 | /**
282 | * @param \SimpleXMLElement $xml
283 | *
284 | * @return TextualForecast[]
285 | */
286 | public static function getTextualForecastsFromXml(\SimpleXMLElement $xml)
287 | {
288 | $textual_forecasts = array();
289 |
290 | // Some places to not have textual forecasts
291 | if (!empty($xml->forecast->text)) {
292 | foreach ($xml->forecast->text->location->time as $forecast) {
293 | try {
294 | $textual_forecasts[] = TextualForecast::createTextualForecastFromXml($forecast);
295 | } catch (\Exception $e) {
296 | // Skip those we cant create..
297 | }
298 | }
299 | }
300 |
301 | return $textual_forecasts;
302 | }
303 |
304 | /**
305 | * @param \SimpleXMLElement $xml
306 | * @return Forecast[]
307 | */
308 | public static function getForecastsFromXml(\SimpleXMLElement $xml)
309 | {
310 | $forecasts = array();
311 | foreach ($xml->forecast->tabular->time as $forecast) {
312 | try {
313 | $forecasts[] = Forecast::getForecastFromXml($forecast);
314 | } catch (\RuntimeException $e) {
315 | // Skip those we cant create..
316 | }
317 | }
318 |
319 | return $forecasts;
320 | }
321 |
322 | /**
323 | * Downloads the data from url and store in cache.
324 | *
325 | * @param String $url
326 | * @param String $path
327 | * @param integer $cacheLife
328 | * @return String XML content
329 | */
330 | private static function downloadData($url, $path, $cacheLife)
331 | {
332 | if (!is_readable($path) || ((time() - filemtime($path)) > $cacheLife)) {
333 | $xml_content = file_get_contents($url);
334 |
335 | if (!empty($xml_content)) {
336 | // Only cache if there is content from request
337 | file_put_contents($path, $xml_content);
338 | return $xml_content;
339 | }
340 | }
341 | return file_get_contents($path);
342 | }
343 |
344 | /**
345 | * @param String $language lowercase language string
346 | *
347 | * @return String
348 | */
349 | private static function getApiUrlByLanguage($language)
350 | {
351 | switch ($language) {
352 | case "norwegian":
353 | case "norsk":
354 | case "bokmål":
355 | return self::API_URL."sted/";
356 | break;
357 | case "newnorwegian":
358 | case "nynorsk":
359 | return self::API_URL."stad/";
360 | break;
361 | case "sami":
362 | case "northernsami":
363 | case "davvisámegiella":
364 | return self::API_URL."sadji/";
365 | break;
366 | case "kven":
367 | case "kväani":
368 | return self::API_URL."paikka/";
369 | break;
370 | default:
371 | return self::API_URL."place/";
372 | }
373 | }
374 |
375 | /**
376 | * Checks the response from yr service.
377 | *
378 | * @see getUrlResponseCode()
379 | *
380 | * @param String $url the urls
381 | *
382 | * @return int the response
383 | */
384 | private static function getServiceResponseCode($url)
385 | {
386 | // Check first url
387 | $url1 = self::getUrlResponseCode($url."/forecast_hour_by_hour.xml");
388 |
389 | // If the url is ok, test the other one
390 | if ($url1 == self::SERVICE_OK) {
391 | $url2 = self::getUrlResponseCode($url."/forecast.xml");
392 |
393 | // Since url1 is ok, return code for url2
394 | return $url2;
395 | }
396 |
397 | return $url1;
398 | }
399 |
400 | /**
401 | * There has been found a bug in the yr service that will deny access to the xml files.
402 | * This method tries to work out this issue.
403 | *
404 | * The problem is that if you try a city that has not been visited for a while, you will
405 | * get HTTP response 500 from yr. This will go away after 5-10 requests to yr. So we
406 | * will need to send at least 5 requests if we get HTTP 500.
407 | *
408 | * Thanks to https://github.com/prebenlm for finding the bug
409 | *
410 | * @param String $url full url to the endpoint
411 | *
412 | * @return int Status code
413 | */
414 | private static function getUrlResponseCode($url)
415 | {
416 | for ($i = 0; $i < 7; $i++) {
417 | $resource = curl_init($url);
418 | curl_setopt($resource, CURLOPT_NOBODY, true);
419 | curl_exec($resource);
420 | $retcode = curl_getinfo($resource, CURLINFO_HTTP_CODE);
421 | $type = curl_getinfo($resource, CURLINFO_CONTENT_TYPE);
422 | curl_close($resource);
423 |
424 | if ($retcode === 0) {
425 | throw new \RuntimeException("Check your internet connection");
426 | }
427 |
428 | // This might happend for 5-10 times
429 | // just skipping to next request if this does happen
430 | if ($retcode == 500) {
431 | continue;
432 | }
433 |
434 | // Response is OK, but we are not returning XML
435 | // Most likely malformatted url, like: Norway/Akershus/Nes
436 | if (($retcode == 200 && $type != "text/xml; charset=utf-8")
437 | || $retcode == 404) {
438 | return self::SERVICE_LOCATION_INVALID;
439 | }
440 |
441 | // Response is OK, and the format is xml. Lets go with that
442 | if ($retcode == 200 && $type == "text/xml; charset=utf-8") {
443 | return self::SERVICE_OK;
444 | }
445 | }
446 |
447 | return self::SERVICE_UNKNOWN_STATE;
448 | }
449 | }
450 |
--------------------------------------------------------------------------------
/autoload.php:
--------------------------------------------------------------------------------
1 | =5.3.0"
16 | },
17 |
18 | "autoload": {
19 | "psr-0": {
20 | "Yr" : "."
21 | }
22 | },
23 |
24 | "extra": {
25 | "branch-alias": {
26 | "dev-master": "1.0-dev"
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | #### Current Forecast
2 | ```php
3 | $yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp");
4 |
5 | $forecast = $yr->getCurrentForecast();
6 | printf("Time: %s to %s\n", $forecast->getFrom()->format("H:i"), $forecast->getTo()->format("H:i"));
7 | printf("Temp: %s %s \n", $forecast->getTemperature(), $forecast->getTemperature('unit'));
8 | printf("Wind: %smps %s\n", $forecast->getWindSpeed(), $forecast->getWindDirection('name'));
9 | ```
10 | ```
11 | Time: 16:00 to 17:00
12 | Temp: 8 celsius
13 | Wind: 5.7mps South-southwest
14 | ```
15 |
16 | #### Forecasts in range / hourly forecasts
17 | ```php
18 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp");
19 |
20 | foreach($yr->getHourlyForecasts(strtotime("now"), strtotime("tomorrow")) as $forecast) {
21 | printf("Time: %s, %s degrees\n", $forecast->getFrom()->format("H:i"), $forecast->getTemperature());
22 | }
23 | ```
24 | ```
25 | Time: 16:00, 7 degrees
26 | Time: 17:00, 7 degrees
27 | Time: 18:00, 6 degrees
28 | Time: 19:00, 6 degrees
29 | [...]
30 | ```
31 |
32 | #### Meta info
33 | ```php
34 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp/");
35 |
36 | echo "Location: " . $yr->getName() . "\n";
37 | echo "Country: " . $yr->getCountry() . "\n";
38 | echo "Last update: " . $yr->getLastUpdated()->format("d.m.y H:i") . "\n";
39 | echo "Next update: " . $yr->getNextUpdate()->format("d.m.y H:i") . "\n";
40 | ```
41 | ```
42 | Location: Sandefjord
43 | Country: Norway
44 | Last update: 09.03.14 10:38
45 | Next update: 09.03.14 17:00
46 | ```
47 |
48 | #### Textual forecasts
49 | ```php
50 | $yr = Yr\Yr::create("Norway/Vestfold/Sandefjord/Sandefjord", "/tmp/");
51 |
52 | foreach($yr->getTextualForecasts() as $forecast) {
53 | print $forecast->getTitle() . "\n";
54 | print $forecast->getText() . "\n\n";
55 | }
56 | ```
57 | ```
58 | Sunday and Monday
59 | Østlandet og Telemark: Sørvestlig frisk bris utsatte steder, periodevis sørvestlig liten kuling på kysten. Oppholdsvær og varierende skydekke. Lokal tåke. Svenskegrensa - Stavern: Sørvestlig frisk bris 10, periodevis liten kuling 12. Skiftende skydekke, opphold. Lokal tåke. Mandag morgen forbigående litt regn. Fra mandag formiddag vestlig bris. For det meste pent vær.
60 |
61 | Monday
62 | Østlandet: Sørvestlig bris. Skyet og lokal tåke. Forbigående litt regn sør for Oslo tidlig på dagen. I løpet av formiddagen vestlig bris og for det meste pent vær, først i vest.
63 |
64 | [...]
65 | ```
66 |
67 | #### Weather Stations
68 | ```php
69 | $yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp", 10, null);
70 |
71 | $weather_stations = $yr->getWeatherStations();
72 |
73 | foreach($weather_stations as $station) {
74 | print "Station: {$station->getName()}\n";
75 | print "Temperature: {$station->getForecast()->getTemperature()}\n";
76 | print "Wind Direction: {$station->getForecast()->getWindDirection()}\n";
77 |
78 | print "\n";
79 | }
80 | ```
81 | ```
82 | Station: Oslo (Blindern)
83 | Temperature: 7.6
84 | Wind Direction: SSW
85 |
86 | Station: Bygdøy
87 | Temperature: 7.9
88 | Wind Direction:
89 |
90 | Station: Alna
91 | Temperature: 8.1
92 | Wind Direction: SSW
93 | ```
--------------------------------------------------------------------------------
/examples/current_forecast.php:
--------------------------------------------------------------------------------
1 | getCurrentForecast();
8 | printf("Time: %s to %s\n", $forecast->getFrom()->format("H:i"), $forecast->getTo()->format("H:i"));
9 | printf("Temp: %s %s \n", $forecast->getTemperature(), $forecast->getTemperature('unit'));
10 | printf("Wind: %smps %s\n", $forecast->getWindSpeed(), $forecast->getWindDirection('name'));
11 |
--------------------------------------------------------------------------------
/examples/forecasts_in_range.php:
--------------------------------------------------------------------------------
1 | getHourlyForecasts(strtotime("now"), strtotime("tomorrow")) as $forecast) {
8 | echo sprintf("Time: %s, %s degrees\n", $forecast->getFrom()->format("H:i"), $forecast->getTemperature());
9 | }
10 |
--------------------------------------------------------------------------------
/examples/hourly_forecasts.php:
--------------------------------------------------------------------------------
1 | getHourlyForecasts() as $forecast) {
8 | print $forecast->getFrom()->format("H:i").": ".$forecast->getTemperature()."\n";
9 | }
10 |
--------------------------------------------------------------------------------
/examples/meta_info.php:
--------------------------------------------------------------------------------
1 | getName()."\n";
8 | echo "Country: ".$yr->getCountry()."\n";
9 | echo "Last update: ".$yr->getLastUpdated()->format("d.m.y H:i")."\n";
10 | echo "Next update: ".$yr->getNextUpdate()->format("d.m.y H:i")."\n";
11 |
--------------------------------------------------------------------------------
/examples/periodic_forecasts.php:
--------------------------------------------------------------------------------
1 | getPeriodicForecasts() as $forecast) {
8 | print $forecast->getFrom()->format("H:i").": ".$forecast->getTemperature()."\n";
9 | }
10 |
--------------------------------------------------------------------------------
/examples/textual.php:
--------------------------------------------------------------------------------
1 | getTextualForecasts() as $forecast) {
8 | print $forecast->getTitle()."\n";
9 | print $forecast->getText()."\n\n";
10 | }
11 |
--------------------------------------------------------------------------------
/examples/weather_stations.php:
--------------------------------------------------------------------------------
1 | getWeatherStations();
8 |
9 | foreach ($weather_stations as $station) {
10 | print "Station: {$station->getName()}\n";
11 | print "Temperature: {$station->getForecast()->getTemperature()}\n";
12 | print "Wind Direction: {$station->getForecast()->getWindDirection()}\n";
13 |
14 | print "\n";
15 | }
16 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tests
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/scripts/download_symbols.php:
--------------------------------------------------------------------------------
1 | /dev/null 2>&1 &");
112 | setProgress(++$counter, "wind");
113 |
114 | for ($i = 0; $i <= 1000; $i += 25) {
115 | $num = str_pad($i, 4, "0", STR_PAD_LEFT);
116 |
117 | for ($angle_deg = 0; $angle_deg <= 355; $angle_deg += 5) {
118 | $angle = str_pad($angle_deg, 3, "0", STR_PAD_LEFT);
119 | exec("cd $path_wind && $downloader https://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.$num.$angle.png > /dev/null 2>&1 &");
120 | setProgress(++$counter, "wind");
121 | }
122 | }
123 |
124 | // Download sun icons
125 | // Forecast::getSymbol("var")
126 | foreach ($images as $image) {
127 | exec("cd $path_general && $downloader https://symbol.yr.no/grafikk/sym/b200/$image.png > /dev/null 2>&1 &");
128 | setProgress(++$counter, "sun");
129 | }
130 |
131 | // Download moon icons
132 | // Forecast::getSymbol("var")
133 | for ($i = 0; $i <= 99; $i++) {
134 | $num = str_pad($i, 2, "0", STR_PAD_LEFT);
135 | foreach ($images_mf as $image_mf) {
136 | exec("cd $path_moon && $downloader https://symbol.yr.no/grafikk/sym/b200/mf/$image_mf.$num.png > /dev/null 2>&1 &");
137 | setProgress(++$counter, "moon");
138 | }
139 | }
140 |
141 | echo "\nDone! Downloaded $counter files\n";
142 |
143 | // A function to update counter
144 | function setProgress($current, $thing)
145 | {
146 | global $max;
147 | global $sleep_time;
148 | echo "\r" . chr(27) . "[K" . "Downloading... ($thing) ($current files) " . ((int)(($current / $max) * 100)) . "%";
149 | usleep($sleep_time);
150 | }
151 |
--------------------------------------------------------------------------------
/scripts/symbols/dummy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eigan/yr-php-library/2c2059a9b6596d1b56e9fdaf4cce0e2355b6d6e7/scripts/symbols/dummy
--------------------------------------------------------------------------------
/test.php:
--------------------------------------------------------------------------------
1 | include "test.php";
8 | */
9 |
10 | // Include the classfiles once
11 | include_once "Yr/Yr.php";
12 | include_once "Yr/Forecast.php";
13 |
14 | // This is not set by default in ini (OSX),
15 | // so override to standard norwegian to avoid warnings
16 | date_default_timezone_set("Europe/Oslo");
17 |
18 | // Saving you
19 | set_error_handler(function ($errno, $msg) {
20 | // Just print the error
21 | echo "PHP Error: ".$msg."\n";
22 |
23 | // Do not go to internal php error handler
24 | return true;
25 | });
26 |
27 | // Possible to override default values
28 | $location = !isset($location) ? "Norway/Vestfold/Sandefjord/Sandefjord" : $location;
29 | $cache_path = !isset($cache_path) ? "/tmp" : $cache_path;
30 | $cache_life = !isset($cache_life) ? 10 : $cache_life;
31 | $language = !isset($language) ? "english" : $language;
32 |
33 | // Initialize yr object
34 | $yr = Yr\Yr::create($location, $cache_path, $cache_life, $language);
35 |
36 | // Notice user if the yr object was created
37 | if ($yr instanceof Yr\Yr) {
38 | print "An Yr object is now available on ".'$yr';
39 | }
40 |
--------------------------------------------------------------------------------
/tests/Yr/ForecastTest.php:
--------------------------------------------------------------------------------
1 | yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp");
8 | $this->forecast = $this->yr->getCurrentForecast();
9 | }
10 |
11 | public function testIsForecast()
12 | {
13 | $this->assertInstanceOf("Yr\Forecast", $this->forecast);
14 | }
15 |
16 | /**
17 | * Testing missing data from xml
18 | *
19 | * @expectedException \RuntimeException
20 | */
21 | public function testGetForecastFromXmlInvalid()
22 | {
23 | Yr\Forecast::getForecastFromXml(new \SimpleXMLElement(' '));
30 | }
31 |
32 | /**
33 | * Testing missing data from xml
34 | *
35 | * @expectedException \RuntimeException
36 | */
37 | public function testGetForecastFromXmlInvalid2()
38 | {
39 | Yr\Forecast::getForecastFromXml(new \SimpleXMLElement(' '));
46 | }
47 |
48 | public function testGetSymbol()
49 | {
50 | $symbol = $this->forecast->getSymbol();
51 | $this->assertTrue(is_string($symbol) && !empty($symbol));
52 | $symbol = $this->forecast->getSymbol("number");
53 | $this->assertTrue(is_string($symbol) && !empty($symbol));
54 | $symbol = $this->forecast->getSymbol("name");
55 | $this->assertTrue(is_string($symbol) && !empty($symbol));
56 | $symbol = $this->forecast->getSymbol("var");
57 | $this->assertTrue(is_string($symbol) && !empty($symbol));
58 | }
59 |
60 | public function testGetPrecipitation()
61 | {
62 | $precipitation = $this->forecast->getPrecipitation();
63 | $this->assertTrue(!empty($precipitation) || $precipitation === "0");
64 | }
65 |
66 | public function testSetPrecipitation()
67 | {
68 | $testArray = array("value" => "1", 'minvalue' => 1, 'maxvalue' => 1);
69 | $this->forecast->setPrecipitation($testArray);
70 |
71 | $this->assertEquals($this->forecast->getPrecipitation("value"), $testArray['value']);
72 | $this->assertEquals($this->forecast->getPrecipitation("minvalue"), $testArray['minvalue']);
73 | $this->assertEquals($this->forecast->getPrecipitation("maxvalue"), $testArray['maxvalue']);
74 | }
75 |
76 | public function testGetWindDirection()
77 | {
78 | $wind_direction = $this->forecast->getWindDirection();
79 | $this->assertTrue(is_string($wind_direction) && !empty($wind_direction));
80 | $wind_direction = $this->forecast->getWindDirection("deg");
81 | $this->assertTrue(is_string($wind_direction) && !empty($wind_direction));
82 | $wind_direction = $this->forecast->getWindDirection("code");
83 | $this->assertTrue(is_string($wind_direction) && !empty($wind_direction));
84 | $wind_direction = $this->forecast->getWindDirection("name");
85 | $this->assertTrue(is_string($wind_direction) && !empty($wind_direction));
86 | }
87 |
88 | public function testGetTemperature()
89 | {
90 | $temperature = $this->forecast->getTemperature();
91 | $this->assertTrue(is_string($temperature) && ($temperature == 0 || !empty($temperature)));
92 | $temperature = $this->forecast->getTemperature("unit");
93 | $this->assertTrue(is_string($temperature) && !empty($temperature));
94 | $temperature = $this->forecast->getTemperature("value");
95 | $this->assertTrue(is_string($temperature) && ($temperature == 0 || !empty($temperature)));
96 | }
97 |
98 | public function testGetPressure()
99 | {
100 | $pressure = $this->forecast->getPressure();
101 | $this->assertTrue(is_string($pressure) && !empty($pressure));
102 | $pressure = $this->forecast->getPressure("unit");
103 | $this->assertTrue(is_string($pressure) && !empty($pressure));
104 | $pressure = $this->forecast->getPressure("value");
105 | $this->assertTrue(is_string($pressure) && !empty($pressure));
106 | }
107 |
108 | public function testSetPressure()
109 | {
110 | $testArray = array("unit" => "m", 'value' => 1);
111 | $this->forecast->setPressure($testArray);
112 |
113 | $this->assertEquals($this->forecast->getPressure("unit"), $testArray['unit']);
114 | $this->assertEquals($this->forecast->getPressure("value"), $testArray['value']);
115 | }
116 |
117 | public function testGetWindIconKey()
118 | {
119 | $icon = $this->forecast->getWindIconKey();
120 | $this->assertTrue(!empty($icon) && is_string($icon));
121 | }
122 |
123 | public function testGetWindIconKey0()
124 | {
125 | $this->forecast->setWindSpeed(array('mps' => 0.2, 'name' => "slow"));
126 |
127 | $this->assertEquals(0, $this->forecast->getWindIconKey());
128 | }
129 |
130 | public function testGetPeriod()
131 | {
132 | $period = $this->forecast->getPeriod();
133 | $this->assertTrue(is_numeric($period) || is_null($period));
134 | }
135 |
136 | public function testSetPeriod()
137 | {
138 | $this->forecast->setPeriod(1);
139 | $this->assertEquals(1, $this->forecast->getPeriod());
140 | }
141 |
142 | public function testSetFrom()
143 | {
144 | $date = new \DateTime();
145 | $this->forecast->setFrom($date);
146 |
147 | $this->assertEquals($date, $this->forecast->getFrom());
148 | }
149 |
150 | public function testSetTo()
151 | {
152 | $date = new \DateTime();
153 | $this->forecast->setTo($date);
154 |
155 | $this->assertEquals($date, $this->forecast->getTo());
156 | }
157 |
158 | public function testToArray()
159 | {
160 | $array = $this->forecast->toArray();
161 |
162 | $this->assertTrue(is_array($array));
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/tests/Yr/LocationTest.php:
--------------------------------------------------------------------------------
1 | location = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp");
8 | }
9 | public function testGetHourlyForecasts()
10 | {
11 | $forecasts = $this->location->getHourlyForecasts();
12 | $this->assertTrue(is_array($forecasts) && count($forecasts) > 0);
13 |
14 | $forecasts = $this->location->getHourlyForecasts(strtotime("now"), strtotime("tomorrow"));
15 | $this->assertTrue(is_array($forecasts) && count($forecasts) > 0);
16 | }
17 |
18 | public function testGetPeriodicForecasts()
19 | {
20 | $forecasts = $this->location->getPeriodicForecasts();
21 | $this->assertTrue(is_array($forecasts) && count($forecasts) > 0);
22 |
23 | $forecast = reset($forecasts);
24 | $this->assertInstanceOf("Yr\Forecast", $forecast);
25 |
26 | $forecasts = $this->location->getPeriodicForecasts(strtotime("now"), strtotime("tomorrow"));
27 | $this->assertTrue(is_array($forecasts) && count($forecasts) > 0);
28 |
29 | $forecast = reset($forecasts);
30 | $this->assertInstanceOf("Yr\Forecast", $forecast);
31 | }
32 |
33 | public function testGetForecastAt()
34 | {
35 | $this->assertInstanceOf("Yr\Forecast", $this->location->getForecastAt(strtotime("now")));
36 | }
37 |
38 | public function testGetWeatherStations()
39 | {
40 | $stations = $this->location->getWeatherStations();
41 | $this->assertTrue(is_array($stations) && count($stations) > 0);
42 |
43 | $station = reset($stations);
44 | $this->assertInstanceOf("Yr\WeatherStation", $station);
45 | }
46 |
47 | public function testGetName()
48 | {
49 | $name = $this->location->getName();
50 | $this->assertTrue(is_string($name) && !empty($name));
51 | }
52 |
53 | public function testGetType()
54 | {
55 | $type = $this->location->getType();
56 | $this->assertTrue(is_string($type) && !empty($type));
57 | }
58 |
59 | public function testGetCountry()
60 | {
61 | $country = $this->location->getCountry();
62 | $this->assertTrue(is_string($country) && !empty($country));
63 | }
64 |
65 | public function testGetTimezone()
66 | {
67 | $timezone = $this->location->getTimezone();
68 | $this->assertTrue(is_string($timezone) && !empty($timezone));
69 | }
70 |
71 | public function testgetLatLong()
72 | {
73 | $latLong = $this->location->getLatLong();
74 |
75 | $this->assertTrue(is_array($latLong));
76 |
77 | $this->assertArrayHasKey("lat", $latLong);
78 | $this->assertArrayHasKey("long", $latLong);
79 | }
80 |
81 | public function testGetCredit()
82 | {
83 | $credit_text = $this->location->getCreditText();
84 | $this->assertTrue(is_string($credit_text) && !empty($credit_text));
85 | $credit_url = $this->location->getCreditUrl();
86 | $this->assertTrue(is_string($credit_url) && !empty($credit_url));
87 | }
88 |
89 | public function testGetLinks()
90 | {
91 | $this->assertTrue(is_array($this->location->getLinks()));
92 | }
93 |
94 | public function testGetCurrentForecast()
95 | {
96 | $this->assertInstanceOf("Yr\Forecast", $this->location->getCurrentForecast());
97 | }
98 |
99 | public function testGetSunrise()
100 | {
101 | $this->assertInstanceOf("\Datetime", $this->location->getSunrise());
102 | }
103 |
104 | public function testGetSunset()
105 | {
106 | $this->assertInstanceOf("\Datetime", $this->location->getSunset());
107 | }
108 |
109 | public function testGetNextUpdate()
110 | {
111 | $this->assertInstanceOf("\Datetime", $this->location->getNextUpdate());
112 | }
113 |
114 | public function testGetLastUpdated()
115 | {
116 | $this->assertInstanceOf("\Datetime", $this->location->getLastUpdated());
117 | }
118 |
119 | public function testToArray()
120 | {
121 | $array = $this->location->toArray();
122 |
123 | $this->assertTrue(is_array($array));
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/tests/Yr/TextualForecastTest.php:
--------------------------------------------------------------------------------
1 | yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp");
8 | $forecasts = $this->yr->getTextualForecasts();
9 | $this->forecast = reset($forecasts);
10 | }
11 |
12 | /**
13 | * @expectedException \InvalidArgumentException
14 | */
15 | public function testInvalidForecast()
16 | {
17 | new Yr\TextualForecast("", "", new \Datetime());
18 | }
19 |
20 | public function testGetTitle()
21 | {
22 | $title = $this->forecast->getTitle();
23 |
24 | $this->assertTrue(is_string($title) && !empty($title));
25 | }
26 |
27 | public function testGetText()
28 | {
29 | $text = $this->forecast->getText();
30 |
31 | $this->assertTrue(is_string($text) && !empty($text));
32 | }
33 |
34 | public function testGetFrom()
35 | {
36 | $from = $this->forecast->getFrom();
37 | $this->assertInstanceOf("\Datetime", $from);
38 | }
39 |
40 | public function testGetTo()
41 | {
42 | $to = $this->forecast->getTo();
43 |
44 | $this->assertInstanceOf("\Datetime", $to);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/Yr/WeatherStationTest.php:
--------------------------------------------------------------------------------
1 | yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp");
8 | $stations = $this->yr->getWeatherStations();
9 | $this->station = reset($stations);
10 | }
11 |
12 | public function testGetName()
13 | {
14 | $name = $this->station->getName();
15 | $this->assertTrue(is_string($name) && !empty($name), "getName() is empty or not string");
16 | }
17 |
18 | public function testGetDistance()
19 | {
20 | $distance = $this->station->getDistance();
21 | $this->assertTrue(is_numeric($distance) && !empty($distance), "getDistance() is empty or not numeric");
22 | }
23 |
24 | public function testgetLatLong()
25 | {
26 | $latLong = $this->station->getLatLong();
27 |
28 | $this->assertTrue(is_array($latLong));
29 |
30 | $this->assertArrayHasKey("lat", $latLong);
31 | $this->assertArrayHasKey("long", $latLong);
32 | }
33 |
34 | public function testGetSource()
35 | {
36 | $source = $this->station->getSource();
37 |
38 | $this->assertTrue(is_string($source) && !empty($source), "getSource() is not string or empty");
39 | }
40 |
41 | public function testGetForecast()
42 | {
43 | $forecast = $this->station->getForecast();
44 |
45 | $this->assertInstanceOf("Yr\Forecast", $forecast);
46 | }
47 |
48 | public function testSetForecast()
49 | {
50 | $forecast = new Yr\Forecast();
51 | $this->station->setForecast($forecast);
52 |
53 | $this->assertEquals($forecast, $this->station->getForecast());
54 | }
55 |
56 | public function testToArray()
57 | {
58 | $array = $this->station->toArray();
59 |
60 | $this->assertTrue(is_array($array) && count($array) > 3);
61 |
62 | $this->assertArrayHasKey('name', $array);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/Yr/YrTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf("Yr\Location", $yr);
10 | }
11 |
12 | public function testCreateFresh()
13 | {
14 | $cache_dir = "/tmp/phpyr".time();
15 | mkdir($cache_dir);
16 |
17 | $yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", $cache_dir, 10, "english");
18 | $this->assertInstanceOf("Yr\Location", $yr);
19 | }
20 |
21 | public function testCreateNorwegian()
22 | {
23 | $yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp", 10, "norwegian");
24 | $this->assertInstanceOf("Yr\Location", $yr);
25 | }
26 |
27 | public function testCreateNewNorwegian()
28 | {
29 | $yr = Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/tmp", 10, "newnorwegian");
30 | $this->assertInstanceOf("Yr\Location", $yr);
31 | }
32 |
33 | /**
34 | * @expectedException \InvalidArgumentException
35 | */
36 | public function testCreateInvalidLocationArgument()
37 | {
38 | Yr\Yr::create("", "/tmp", 10, null);
39 | }
40 |
41 | /**
42 | * @expectedException \RuntimeException
43 | */
44 | public function testCreateInvalidLocation2()
45 | {
46 | Yr\Yr::create("5855/invalid", "/tmp", 10, null);
47 | }
48 |
49 | /**
50 | * @expectedException \RuntimeException
51 | */
52 | public function testCreateInvalidLocation()
53 | {
54 | Yr\Yr::create("Norway/Vestfold/nocity/Nocity", "/tmp", 10, null);
55 | }
56 |
57 | /**
58 | * @expectedException \RuntimeException
59 | */
60 | public function testCreateNotWriteableCache()
61 | {
62 | Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "/this/dir/does/not/exist/", 10, null);
63 | }
64 |
65 | /**
66 | * @expectedException \InvalidArgumentException
67 | */
68 | public function testCreateInvalidCachePath()
69 | {
70 | Yr\Yr::create("Norway/Oslo/Oslo/Oslo", "", 10, null);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------