Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Archive /

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo

MASHUP with cashing


Go to End


3 Posts   2124 Views

Avatar
freeyland

Community Member, 22 Posts

14 August 2007 at 9:16pm

Edited: 14/08/2007 9:27pm

The new RestfulService.php


<?php

/**
 * RestfulService class allows you to consume various RESTful APIs.
 * Through this you could connect and aggregate data of various web services.
 */
class RestfulService extends ViewableData {
	protected $baseURL;
	protected $queryString;
	protected $rawXML;
	protected $errorTag;
	protected $cachedir;
	protected $cache_location;
	protected $cache_expires;
	protected $cache_lifetime;
	protected $source;       // cache or live
	protected $cashed_Content;
	
	
	function __construct($base,$locationname,$lifetime){
		$this->baseURL = $base;
		$this->cache_lifetime = $lifetime;
		
		if (isset($_ENV["TEMP"]))
		  $cachedir=$_ENV["TEMP"]."/silverstripe-cache";
		else if (isset($_ENV["TMP"]))
		  $cachedir=$_ENV["TMP"]."/silverstripe-cache";
		else if (isset($_ENV["TMPDIR"]))
		  $cachedir=$_ENV["TMPDIR"]."/silverstripe-cache";
		else
		// Default Cache Directory  
		  $cachedir="/tmp";
		  
		$cachedir=str_replace('\\\\','/',$cachedir);
		if (substr($cachedir,-1)!='/') $cachedir.='/'; 
		
		$this->cache_location = $cachedir.$locationname;
	}
	
	/**
 	* Sets the Query string parameters to send a request.
 	* @param params An array passed with necessary parameters. 
 	*/
	function setQueryString($params=NULL){
		$this->queryString = http_build_query($params,'','&');
	}
	
	protected function constructURL(){
		return "$this->baseURL?$this->queryString";
	}
	
	/**
 	* Connects to the RESTful service and gets its response.
 	* TODO implement authentication via cURL for
 	*/
	
	function connect(){
		$url = $this->constructURL();
		
		if ($this->readcache()) { //TRUE MEANS THAT CASH WILL BE READ
			$this->source = 'cache';
		}else{
			$this->source = 'live';
			$ch = curl_init();
			$timeout = 5;
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
			$this->rawXML = curl_exec($ch);
			curl_close($ch);
								
			//Debug::show($url);			
			//Try using file_get_contents if cURL is not installed in your system.
			//$this->rawXML = file_get_contents($url);
			if($this->rawXML != "")
				if($this->checkErrors == true)
					return $this->errorCatch($this->rawXML);
				else
					return $this->rawXML;
			else
				user_error("Invalid Response (maybe your calling to wrong URL or server unavailable)", E_USER_ERROR);
		}
	}
	
	
	function readcache()
	{
		if (file_exists($this->cache_location) && filemtime($this->cache_location)<time()){
			$content=@file_get_contents($this->cache_location);
			if ($content==false) return false;
			$intweather = unserialize($content);
			$this->cashed_Content = $intweather;
			return true;
		}else{
			return false;
		}
	}
	
	function writecache($output) {
		
		$cache_expires= time() + $this->cache_lifetime;
		$fp = fopen($this->cache_location, "w");
		fwrite($fp, serialize($output));
		fclose($fp);
	}

	
	/**
 	* Gets attributes as an array, of a particular type of element.
 	* @params xml - the source xml to parse, this could be the original response received.
 	* @params collection - parent node which wraps the elements, if available
 	* @params element - element we need to extract the attributes.
 	* Example : <photo id="2636" owner="123" secret="ab128" server="2"> 
 	* returns id, owner,secret and sever attribute values of all such photo elements.
 	*/
	
	function getAttributes($xml, $collection=NULL, $element=NULL){
		if ($this->source == 'live'){
			$xml = new SimpleXMLElement($xml);
			$output = new DataObjectSet();
			
			if($collection)
				$childElements = $xml->{$collection};
			if($element)
				$childElements = $xml->{$collection}->{$element};
			
			if($childElements){
				foreach($childElements as $child){
					$data = array();
					foreach($child->attributes() as $key => $value){
						$data["$key"] = Convert::raw2xml($value);
					}
					
					$output->push(new ArrayData($data));
				}
			}
			
			//Debug::show($output);
		}else if ($this->source == 'cache'){
			$output=$this->cashed_Content;
		}
		return $output;
		
	}
	
	/**
 	* Gets an attribute of a particular element.
 	* @params xml - the source xml to parse, this could be the original response received.
 	* @params collection - parent node which wraps the element, if available
 	* @params element - element we need to extract the attribute
 	* @params attr - name of the attribute
 	*/
	
	function getAttribute($xml, $collection=NULL, $element=NULL, $attr){
		if ($this->source == 'live'){
			$xml = new SimpleXMLElement($xml);
			$attr_value = "";
			
			if($collection)
					$childElements = $xml->{$collection};
				if($element)
					$childElements = $xml->{$collection}->{$element};
				
				if($childElements)
					$attr_value = (string) $childElements[$attr];
				
				$this->output= Convert::raw2xml($attr_value);
				
				$this->writecache($this->output);
				
		}else if ($this->source == 'cache'){
			$output=$this->cashed_Content;
		}
		return $output;
	}
	
	/**
 	* Gets set of node values as an array. 
 	* When you get to the depth in the hierachchy use node_child_subchild syntax to get the value.
 	* @params xml - the source xml to parse, this could be the original response received.
 	* @params collection - parent node which wraps the elements, if available
 	* @params element - element we need to extract the node values.
 	*/
	
	function getValues($xml, $collection=NULL, $element=NULL){

		if ($this->source == 'live'){

			$xml = new SimpleXMLElement($xml);
			$output = new DataObjectSet();
			
				$childElements = $xml;
			if($collection)
				$childElements = $xml->{$collection};
			if($element)
				$childElements = $xml->{$collection}->{$element};
			
			if($childElements){
				foreach($childElements as $child){
					$data = array();
					$this->getRecurseValues($child,$data);			
					$output->push(new ArrayData($data));
				}
			}
			$this->writecache($output);
		}else if ($this->source == 'cache'){
			$output =$this->cashed_Content;
		}
		return $output;
	}
	
	protected function getRecurseValues($xml,&$data,$parent=""){
		$child_count = 0;
		foreach($xml as $key=>$value)
		{
			$child_count++;    
			$k = ($parent == "") ? (string)$key : $parent . "_" . (string)$key;
			if($this->getRecurseValues($value,$data,$k) == 0)  // no childern, aka "leaf node"
				$data[$k] = Convert::raw2xml($value);  
		}
		return $child_count;
			
	}
	
	/**
 	* Gets a single node value. 
 	* @params xml - the source xml to parse, this could be the original response received.
 	* @params collection - parent node which wraps the elements, if available
 	* @params element - element we need to extract the node value.
 	*/
	
	function getValue($xml, $collection=NULL, $element=NULL){
		if ($this->source == 'live'){
			$xml = new SimpleXMLElement($xml);
			
			if($collection)
				$childElements = $xml->{$collection};
			if($element)
				$childElements = $xml->{$collection}->{$element};
			
			if($childElements)
				$output = Convert::raw2xml($childElements);
				$this->writecache($output);
		}else if ($this->source == 'cache'){
			$output = $this->cashed_Content;
		}
		return $output;
		
	}
	
	function searchValue($xml, $node=NULL){
		if ($this->source == 'live'){
			$xml = new SimpleXMLElement($xml);
			$childElements = $xml->xpath($node);
		
			if($childElements)
				$output  = Convert::raw2xml($childElements[0]);
			$this->writecache($output);
		}else if ($this->source == 'cache'){
			$output =$this->cashed_Content;
		}
		return $output;
	}
	
	function searchAttributes($xml, $node=NULL){
		
		echo $this->source;
		
		if ($this->source == 'live'){
			$xml = new SimpleXMLElement($xml);
			$output = new DataObjectSet();
		
			$childElements = $xml->xpath($node);
			
			if($childElements)
			foreach($childElements as $child){
			$data = array();
				foreach($child->attributes() as $key => $value){
					$data["$key"] = Convert::raw2xml($value);
				}
				
				$output->push(new ArrayData($data));
			}
				
			//Debug::show($output);
			$this->writecache($output);
		}else if ($this->source == 'cache'){
			$output =$this->cashed_Content;
		}		
		return $output;
	}
	

}
?>

The new mashupsample.php:


<?

class MashupSample extends Page {
	static $db = array(
	);
	static $has_one = array(
   );
}

class MashupSample_Controller extends Page_Controller {

	//Test on AMAZON AWS testing
	function AmazonProducts(){
		
		$cash_lifetime=3*60*60;  // 3 hours		
		$location_name="Amazon"; //Has to be unique because for every new RestfulService you have a new cash file
		$feed="http://ecs.amazonaws.com/onca/xml";

		$amazon = new RestfulService($feed,$location_name,$cash_lifetime);
		$params = array(
				"Service"=>"AWSECommerceService",
				"AWSAccessKeyId"=>"0QZ1AAT31TZ9RNVANY82",
				"Operation"=>"ItemSearch",
				"SearchIndex"=>"Books",
				"Title"=>"Harry Potter"
		);
		$amazon->setQueryString($params);
		$conn = $amazon->connect();
		$result = $amazon->getValues($conn, "Items", "Item");
		//Debug::show($result);
		return $result;
	}
	
	
	function YahooWeather(){
		
		$cash_lifetime=0;  // no caching	
		$location_name="YahooWeather"; //Has to be unique because for every new RestfulService you have a new cash file
		$feed="http://localhost/projects/forecastrss.xml";

		$yw = new RestfulService($feed,$location_name,$cash_lifetime);
		$params = array(
				"u"=>"C",
				"p"=>"AUXX0118"
		);
		$yw->setQueryString($params);
		$conn = $yw->connect();
		
		$result = $yw->searchAttributes($conn, "//yweather:condition"); 
		
		return $result;
	}
	
	
}

?>

Avatar
laktek

Google Summer of Code Hacker, 76 Posts

15 August 2007 at 1:20am

Freeyland, thank you very much for your contribution. I'll go through this and merge these modification with the trunk soon.

Avatar
Ingo

Forum Moderator, 801 Posts

17 August 2007 at 8:15am

cool...but, can you please place long code-parts externally? my finger hurts from scrolling through googe reader *g*. http://pastie.caboo.se/ is pretty good for this.