Yahoo weather component
Yahoo! developer network provides a RSS based API to access weather information for locations all around the world. The component has a method named get_weather($locationCode,$degreeUnit) that retrieves the weather information for the given location code and outputs the data in an easy to use array. Please read "http://developer.yahoo.com/weather/" for more information about the location code and degree unit. I will provide a tutorial as soon as possible.
Component Class:
<?php
/* Yahoo! Weather API component for Cakephp
* @author Arash Hemmat www.hemmat.biz
* @version 1.2 some bugs has been fixed.
* @license http://www.opensource.org/licenses/mit-license.php
* Special thanks to "Ed Eliot" (http://www.ejeliot.com/blog/38) ,I used his code for this component.
*/
/*
* Yahoo weather component class
*/
class yahooWeatherComponent extends Object
{
/*
* @var bool
*/
var $controller = true;
/*
* @var array
*/
var $errors=array();
/*
* @var string
*/
var $content;
/*
* The url of Yahoo! weather API
* @var string
*/
var $WEATHER_API_URL='http://weather.yahooapis.com/forecastrss?p=';
/*
* THe address for images, you need to change this if you want to use your own images.
* @var string
*/
var $WEATHER_IMAGE_BASE='http://l.yimg.com/us.yimg.com/i/us/we/52/';
/*
* initialization
* @param bool $controller
*/
function startup(&$controller)
{
$this->controller =& $controller;
}
/*
* Get the weather information for given location code
* @param string $locationCode a code that represent a location in Yahoo weather system
* @param string $degreeUnit it could be f: Fahrenheit or c: Celsius
* @param bool $translate this parametr indicates if the result should be translated of not
* @return array|bool $result
*/
function get_weather($locationCode,$degreeUnit='c')
{
if($this->content = file_get_contents($this->WEATHER_API_URL.$location_code.'&u='.$degreeUnit))
{
$result['location']=$this->GetTagAttributes('yweather:location');
$result['condition']=$this->GetTagAttributes('yweather:condition');
$result['units']=$this->GetTagAttributes('yweather:units');
$result['wind']=$this->GetTagAttributes('yweather:wind');
$result['atmosphere']=$this->GetTagAttributes('yweather:atmosphere');
$result['astronomy']=$this->GetTagAttributes('yweather:astronomy');
$result['geo:lat']=$this->GetTagValue('geo:lat');
$result['geo:long']=$this->GetTagValue('geo:long');
$result['link']=explode('*',$this->GetTagValue('link'));
$result['pubDate']=$this->GetTagValue('pubDate');
$result['description']=$this->GetTagValue('description');
$result['image_url']=$this->WEATHER_IMAGE_BASE.$result['condition']['code'].'.gif';
$forecasts=$this->GetTagAttributes('yweather:forecast');
$result['tonight_forecast']=$forecasts[0];
$result['tonight_forecast']['image_url']=$this->WEATHER_IMAGE_BASE.$result['tonight_forecast']['code'].'.gif';
$result['tomorrow_forecast']=$forecasts[1];
$result['tomorrow_forecast']['image_url']=$this->WEATHER_IMAGE_BASE.$result['tomorrow_forecast']['code'].'.gif';
return $result;
}
else
{
$this->errors[]='Unable to connect to yahoo api.';
return false;
}
}
/*
* @param string $sTag
* @return bool
*/
function GetTagValue($sTag)
{
$aMatches = array();
if (preg_match("/<$sTag>([^<]*)<\/$sTag>/i", $this->content, $aMatches))
{
$aResult = array();
$aResult['value'] = $aMatches[1];
return trim($aMatches[1]);
}
return false;
}
/*
* @param string $sTag
* @return string $aResult
*/
function GetTagAttributes($sTag)
{
$aMatches = array();
if (preg_match_all("/<$sTag([^\/]*)\/>/i", $this->content, $aMatches))
{
$aResult = array();
for ($i = 0; $i < count($aMatches[1]); $i++)
{
$aSubMatches = array();
if (preg_match_all("/([^=]+)=\"([^\"]*)\"/i", $aMatches[1][$i], $aSubMatches))
{
for ($j = 0; $j < count($aSubMatches[1]); $j++)
{
$aResult[$i][trim($aSubMatches[1][$j])] = trim($aSubMatches[2][$j]);
}
}
}
$iNumResults = count($aResult);
if ($iNumResults > 1)
{
return $aResult;
} elseif ($iNumResults == 1)
{
return $aResult[0];
}
}
return false;
}
}
?>








In your controller you will need to add:
var $components = 'yahooWeather';
.....
$this->set('yahooWeather', $this->yahooWeather->get_weather( $locationCode ,'c'));
Where the $locationCode can be any of the codes in this link:
http://www.edg3.co.uk/snippets/weather-location-codes/
And do whatever you need to with $yahooWeather in your view
Hope it helps!
Rafa
To go back to the default, change Configure::read('weather.city') to $locationCode and Configure::read('weather.units') to $degreeUnit
function get_weather() {
// Set our cache for 1 hour
Cache::set(array('duration' => '+1 hour'));
// Check if we have anything already cached
$weather = Cache::read('weather-' . Configure::read('weather.city'));
// If we do, then read it into $this->data
if($weather !== false) {
$this->content = unserialize(Cache::read('weather-' . Configure::read('weather.city')));
}
// If we don't, fetch it from Yahoo, put it into $this->data, and then cache it
else {
$this->content = file_get_contents($this->WEATHER_API_URL.Configure::read('weather.city').'&u='.Configure::read('weather.units'));
Cache::write('weather-' . Configure::read('weather.city'), serialize($this->content));
}
// Take all the info from Yahoo and put into a usable array
if($this->content) {
$result['location']=$this->GetTagAttributes('yweather:location');
$result['condition']=$this->GetTagAttributes('yweather:condition');
$result['units']=$this->GetTagAttributes('yweather:units');
$result['wind']=$this->GetTagAttributes('yweather:wind');
$result['atmosphere']=$this->GetTagAttributes('yweather:atmosphere');
$result['astronomy']=$this->GetTagAttributes('yweather:astronomy');
$result['geo:lat']=$this->GetTagValue('geo:lat');
$result['geo:long']=$this->GetTagValue('geo:long');
$result['link']=explode('*',$this->GetTagValue('link'));
$result['pubDate']=$this->GetTagValue('pubDate');
$result['description']=$this->GetTagValue('description');
$forecasts=$this->GetTagAttributes('yweather:forecast');
$result['tonight_forecast']=$forecasts[0];
$result['tomorrow_forecast']=$forecasts[1];
// code 3200 is Yahoo's not available code, so if we get it, clear the cache
if($result['condition'] == '3200') {
Cache::delete('weather-' . Configure::read('weather.city'));
}
return $result;
} else {
$this->errors[]='Unable to connect to yahoo api.';
return false;
}
}
Also, I added a function to the component that creates a small table with today's, tonight's and tomorrows weather: Regrettably I cannot add that code here without screwing up the layout of that code.
There is a typo in the get_weather function;
if($this->content =file_get_contents( $this->WEATHER_API_URL.$location_code.'&u='.$degreeUnit))
$location_code should be $locationCode.
Plus the first regex for the GetTagAttributes function has a slight issue ...
preg_match_all("/<$sTag([^\/]*)\/>/i", $this->content,$aMatches)
This will ignore any yweather:forecast with a '/' in the them such as text="Rain/Snow".
Looking at the XML that the Yahoo RSS feed dishes out, there doesn't seem to be any need to strip '/' from the code for the GetTagAttributes function so I have this working ok using a simpler regex as follows;
"/<$sTag(.*)\/>/i"
Thanks again.
Currently I prefer not to change that regex.
Thanks for your tips, I appreciate your help.
Comments are closed for articles over a year old