1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20:
21: class Horde_Service_Weather_Wwo extends Horde_Service_Weather_Base
22: {
23:
24: const API_URL = 'http://free.worldweatheronline.com/feed/weather.ashx';
25: const SEARCH_URL = 'http://www.worldweatheronline.com/feed/search.ashx';
26:
27: public $title = 'World Weather Online';
28: public $link = 'http://worldweatheronline.com';
29:
30: protected $_key;
31:
32:
33: 34: 35: 36: 37:
38: public $iconMap = array(
39: 'wsymbol_0001_sunny' => '32.png',
40: 'wsymbol_0002_sunny_intervals' => '30.png',
41: 'wsymbol_0003_white_cloud' => '26.png',
42: 'wsymbol_0004_black_low_cloud' => '26.png',
43: 'wsymbol_0006_mist' => '34.png',
44: 'wsymbol_0007_fog' => '20.png',
45: 'wsymbol_0008_clear_sky_night' => '33.png',
46: 'wsymbol_0009_light_rain_showers' => '11.png',
47: 'wsymbol_0010_heavy_rain_showers' => '12.png',
48: 'wsymbol_0011_light_snow_showers' => '14.png',
49: 'wsymbol_0012_heavy_snow_showers' => '16.png',
50: 'wsymbol_0013_sleet_showers' => '7.png',
51: 'wsymbol_0016_thundery_showers' => '0.png',
52: 'wsymbol_0017_cloudy_with_light_rain' => '11.png',
53: 'wsymbol_0018_cloudy_with_heavy_rain' => '12.png',
54: 'wsymbol_0019_cloudy_with_light_snow' => '13.png',
55: 'wsymbol_0020_cloudy_with_heavy_snow' => '16.png',
56: 'wsymbol_0021_cloudy_with_sleet' => '8.png',
57: 'wsymbol_0024_thunderstorms' => '0.png',
58: 'wsymbol_0025_light_rain_showers_night' => '40.png',
59: 'wsymbol_0026_heavy_rain_showers_night' => '30.png',
60: 'wsymbol_0027_light_snow_showers_night' => '41.png',
61: 'wsymbol_0028_heavy_snow_showers_night' => '42.png',
62: 'wsymbol_0029_sleet_showers_night' => '7.png',
63: 'wsymbol_0032_thundery_showers_night' => '47.png',
64: 'wsymbol_0033_cloudy_with_light_rain_night' => '45.png',
65: 'wsymbol_0034_cloudy_with_heavy_rain_night' => '45.png',
66: 'wsymbol_0035_cloudy_with_light_snow_night' => '46.png',
67: 'wsymbol_0036_cloudy_with_heavy_snow_night' => '46.png',
68: 'wsymbol_0037_cloudy_with_sleet_night' => '8.png',
69: 'wsymbol_0040_thunderstorms_night' => '47.png'
70: );
71:
72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82:
83: public function __construct(array $params = array())
84: {
85:
86: if (empty($params['apikey'])) {
87: throw new InvalidArgumentException('Missing required API Key parameter.');
88: }
89: $this->_key = $params['apikey'];
90: unset($params['apikey']);
91: parent::__construct($params);
92: }
93:
94: 95: 96: 97: 98:
99: public function getCurrentConditions($location)
100: {
101: $this->_getCommonElements($location);
102: return $this->_current;
103: }
104:
105: 106: 107: 108: 109:
110: public function getForecast(
111: $location,
112: $length = Horde_Service_Weather::FORECAST_3DAY,
113: $type = Horde_Service_Weather::FORECAST_TYPE_STANDARD)
114: {
115: $this->_getCommonElements($location);
116: return $this->_forecast;
117: }
118:
119: 120: 121: 122: 123: 124: 125: 126: 127:
128: public function searchLocations($location, $type = Horde_Service_Weather::SEARCHTYPE_STANDARD)
129: {
130: switch ($type) {
131: case Horde_Service_Weather::SEARCHTYPE_STANDARD:
132: case Horde_Service_Weather::SEARCHTYPE_IP;
133: return $this->_parseSearchLocations($this->_searchLocations($location));
134: }
135: }
136:
137:
138: public function autocompleteLocation($search)
139: {
140: $url = new Horde_Url(self::SEARCH_URL);
141: $url->add(array(
142: 'query' => $search,
143: 'format' => 'json',
144: 'num_of_results' => 25));
145:
146: return $this->_parseAutocomplete($this->_makeRequest($url));
147: }
148:
149: 150: 151: 152: 153:
154: public function getSupportedForecastLengths()
155: {
156: return array(
157: 3 => Horde_Service_Weather::FORECAST_3DAY,
158: 5 => Horde_Service_Weather::FORECAST_5DAY
159: );
160: }
161:
162: 163: 164: 165: 166: 167:
168: protected function _getCommonElements($location, $length = Horde_Service_Weather::FORECAST_5DAY)
169: {
170: if (!empty($this->_current) && $location == $this->_lastLocation
171: && $this->_lastLength == $length) {
172: return;
173: }
174:
175: $this->_lastLength = $length;
176: $this->_lastLocation = $location;
177:
178: $url = new Horde_Url(self::API_URL);
179:
180: $url->add(array(
181: 'q' => $location,
182: 'num_of_days' => $length,
183: 'includeLocation' => 'yes',
184: 'localObsTime' => 'yes'));
185:
186: $results = $this->_makeRequest($url);
187: $station = $this->_parseStation($results->data->nearest_area[0]);
188:
189:
190: $this->_current = $this->_parseCurrent($results->data->current_condition);
191:
192:
193: $date = $this->_current->time;
194: $station->sunset = new Horde_Date(
195: date_sunset(
196: $date->timestamp(),
197: SUNFUNCS_RET_TIMESTAMP,
198: $station->lat,
199: $station->lon)
200: );
201: $station->sunrise = new Horde_Date(
202: date_sunrise(
203: $date->timestamp(),
204: SUNFUNCS_RET_TIMESTAMP,
205: $station->lat,
206: $station->lon)
207: );
208: $station->time = (string)$date;
209: $this->_station = $station;
210: $this->_forecast = $this->_parseForecast($results->data->weather);
211: }
212:
213: 214: 215: 216: 217: 218: 219:
220: protected function _parseStation($station)
221: {
222: $properties = array(
223:
224: 'name' => $station->areaName[0]->value . ', ' . $station->region[0]->value,
225: 'city' => $station->areaName[0]->value,
226: 'state' => $station->region[0]->value,
227: 'country' => $station->country[0]->value,
228: 'country_name' => '',
229: 'tz' => '',
230: 'lat' => $station->latitude,
231: 'lon' => $station->longitude,
232: 'zip' => '',
233: 'code' => $station->latitude . ',' . $station->longitude
234: );
235:
236: return new Horde_Service_Weather_Station($properties);
237: }
238:
239: 240: 241: 242: 243: 244: 245:
246: protected function _parseForecast($forecast)
247: {
248: $forecast = new Horde_Service_Weather_Forecast_Wwo($forecast, $this);
249: return $forecast;
250: }
251:
252: 253: 254: 255: 256: 257: 258:
259: protected function _parseCurrent($current)
260: {
261:
262: $current = new Horde_Service_Weather_Current_Wwo($current[0], $this);
263: return $current;
264: }
265:
266: protected function _parseAutocomplete($results)
267: {
268: $return = array();
269: if (!empty($results->search_api->result)) {
270: foreach($results->search_api->result as $result) {
271: if (!empty($result->region[0]->value)) {
272: $new = new stdClass();
273: $new->name = $result->areaName[0]->value . ', ' . $result->region[0]->value;
274: $new->code = $result->latitude . ',' . $result->longitude;
275: $return[] = $new;
276: }
277: }
278: }
279:
280: return $return;
281: }
282:
283: 284: 285: 286: 287: 288: 289:
290: protected function _searchLocations($location)
291: {
292: $url = new Horde_Url(self::SEARCH_URL);
293: $url = $url->add(array(
294: 'timezone' => 'yes',
295: 'query' => $location,
296: 'num_of_results' => 10));
297:
298: return $this->_makeRequest($url);
299: }
300:
301: protected function _parseSearchLocations($response)
302: {
303: if (!empty($response->error)) {
304: throw new Horde_Service_Weather_Exception($response->error->msg);
305: }
306:
307:
308:
309:
310: if (!empty($response->search_api->result)) {
311: $results = array();
312: return $this->_parseStation($response->search_api->result[0]);
313: }
314:
315: return array();
316: }
317:
318: 319: 320: 321: 322: 323: 324: 325:
326: protected function _makeRequest(Horde_Url $url)
327: {
328: $url->add(
329: array(
330: 'format' => 'json',
331: 'key' => $this->_key)
332: )->setRaw(true);
333:
334: $cachekey = md5('hordeweather' . $url);
335: if ((!empty($this->_cache) && !$results = $this->_cache->get($cachekey, $this->_cache_lifetime)) ||
336: empty($this->_cache)) {
337: $response = $this->_http->get($url);
338: if (!$response->code == '200') {
339: Horde::logMessage($response->getBody());
340: throw new Horde_Service_Weather_Exception($response->code);
341: }
342: $results = $response->getBody();
343: if (!empty($this->_cache)) {
344: $this->_cache->set($cachekey, $results);
345: }
346: }
347: $results = Horde_Serialize::unserialize($results, Horde_Serialize::JSON);
348: if (!($results instanceof StdClass)) {
349: throw new Horde_Service_Weather_Exception('Error, unable to decode response.');
350: }
351:
352: return $results;
353: }
354:
355: }