Thursday, February 12, 2009

Try Zend Framework vol.12 "Service My Mini City"

Recentry I got a new work making a web site with php.
Then I luckly to get a chance to use Zend Framework again :)

So, I restarted to try Zend Framework!
But, before trying hard one, I wanted to start trying easy one like Zend_Service.
While thinking about it I recall a web service called "My Mini City" which is very fun and exciting.

I wanted a blog tool of it, but could not find it. So I decide to make blog tool of it looks like this.

myminicity

At first, make library which scrapes your MyMiniCity page.

librarly/Hoge/Service/MyMiniCity.php
<?php
/**
* @see Zend_Service_Abstract
*/
require_once 'Zend/Service/Abstract.php';

/**
* Hoge_Service_MyMiniCity is a concrete implementation of the myminicity web service
*/
class Hoge_Service_MyMiniCity extends Zend_Service_Abstract
{
/**
* Basic URI
*/
const API_URI = 'http://%s.myminicity.com';

/**
* XML path
*/
const PATH_XML = '/xml';

/**
* RSS path
*/
const PATH_RSS = '/rss';

/**
* Xml string
*
* @var xml string
*/
protected $_xml;

/**
* Account
*
* @var string city name
*/
protected $_city;

/**
* Constructs a new myminicity Web Service Client
* The myminicity.com requires "Referer" and "User-Agent"
* otherwise you can not get the page.
*
* @param string $city city name
* @return void
*/
public function __construct($city)
{
$this->_city = $city;
self::getHttpClient()->setHeaders('Referer', sprintf(self::API_URI, $city));
self::getHttpClient()->setHeaders('User-Agent', $_SERVER['HTTP_USER_AGENT']);
}

/**
* Get response body.
* @reutrn string response body.
*/
protected function _getResponse($path = '')
{
$uri = sprintf(self::API_URI . $path, $this->_city);
return self::getHttpClient()->setUri($uri)->request()->getBody();
}

/**
* Get Xml data
*
* @return string xml string
*/
protected function _getXml()
{
if ($this->_xml) return $this->_xml;
$this->_xml = $this->_getResponse(self::PATH_XML);
return $this->_xml;
}

/**
* Get Simple Xmle Element
*
* @return object $obj SimpleXmlElement
*/
protected function _getSimpleXmlElement()
{
return simplexml_load_string($this->_getXml());
}

/**
* Convert xml to array
*
* @return array converted array data from xml string.
*/
protected function _xmlToArray()
{
$items = array();
foreach ($this->_getSimpleXmlElement() as $key => $val) {
if ($key == 'region') {
foreach($val->attributes() as $key2 => $val2) {
$items[$key][$key2] = (string) $val2;
}
$items[$key][0] = (string) $val;
}
else if ($key === 'bases') {
foreach($val->attributes() as $key2 => $val2) {
$items[$key][$key2] = (string) $val2;
}
}
else {
$items[$key] = (string) $val;
}
}
return $items;
}

/**
* Flash vars
* Perse string look like below in source
* The purpose of scraping source is to get k parameter.
* so.addParam("FlashVars","name=kawadu&pop=129&ind=36&tra=8&sec=0&env=0&com=0&k=949e4");
*
* @return string flash parameters.
* @throws Exception In case it failed to get flash parameters.
*/
public function getFlashVars()
{
$pattern = '/so.addParam\("FlashVars","(name=.*?&k=.*?)"\)/';
if (preg_match($pattern, $this->_getResponse(), $matches)) {
return $matches[1];
}
throw new Zend_Service_Exception('Could not perse "k" parameter.');
}

/**
* Get embed tag
*
* @param int $height height
* @param int $width width
* @return string embed tag
*/
public function getEmbedTag($height = '100%', $width = '100%', $showdetail = false)
{
$str ='(function(){
city = arguments[0];

html = "<embed "
html += "quality=\"high\" "
html += "allowscriptaccess=\"always\" "
html += "flashvars=\"" + city.flashvars + "\" "
html += "type=\"application/x-shockwave-flash\" "
html += "src=\"http://data.myminicity.com/swf/client.swf?v=5\" "
html += "bgcolor=\"#deecfe\" "
html += "id=\"client\" "
html += "height=\"" + city.height + "\" "
html += "width=\"" + city.width + "\" "
html += "scale=\"scale\" "
html += "name=\"client\" "
html += "></embed>"
document.write(html);

if (city.showdetail) {
html = "<ul>";
html += "<li>name : " + city.name + "</li>";
html += "<li>region : " + city.region + "</li>";
html += "<li>ranking : " + city.ranking + "</li>";
html += "<li>population : " + city.population + "</li>";
html += "<li>incomes : " + city.incomes + "</li>";
html += "<li>unemployment : " + city.unemployment + "</li>";
html += "<li>transport : " + city.transport + "</li>";
html += "<li>criminality : " + city.criminality + "</li>";
html += "<li>pollution : " + city.population + "</li>";
html += "<li>nextnuke : " + city.nextnuke + "</li>";
html += "<li>signatures : " + city.signatures + "</li>";
html += "</ul>";
document.write(html);
}

html = "<ul>";
html += "<li><a href=\"http://" + city.host + "\" target=\"_blank\">Increase population</a></li>";
html += "<li><a href=\"http://" + city.host + "/ind\" target=\"_blank\">Increase industry</a></li>";
html += "<li><a href=\"http://" + city.host + "/tra\" target=\"_blank\">Improve the transport network</a></li>";
html += "<li><a href=\"http://" + city.host + "/sec\" target=\"_blank\">Increase security</a></li>";
html += "<li><a href=\"http://" + city.host + "/env\" target=\"_blank\">Increase environment</a></li>";
html += "<li><a href=\"http://" + city.host + "/com\" target=\"_blank\">Increase business</a></li>";
html += "</ul>";
document.write(html);

})({
height: "' . $height . '",
width: "' . $width .'",
host : "' . $this->host . '",
name: "' . $this->name . '",
region: "' . $this->region . '",
ranking: "' . $this->ranking . '",
population: "' . $this->population . '",
incomes: "' . $this->incomes . '",
unemployment: "' . $this->unemployment . '",
transport: "' . $this->transport . '",
criminality: "' . $this->criminality . '",
pollution: "' . $this->population . '",
nextnuke:"' . $this->nextnuke . '",
signatures:"' . $this->signatures . '",
flashvars:"' . $this->flashvars . '",
showdetail:"' . $showdetail . '"
});
';
return $str;
}

/**
* Get Xml
* @return string xml string.
*/
public function getXml()
{
return $this->_getXml();
}

/**
* Get Rss
* @return string Rss string
*/
public function getRss()
{
return $this->_getResponse(self::PATH_RSS);
}

/**
* Get Json
* get json string from xml data
* @return string json string
*/
public function getJson()
{
require_once 'Zend/Json.php';
return Zend_Json::fromXml($this->_getXml(), false);
}

/**
* Get Array
* Get array values from xml data
*
* @return array data array converted from xml data
*/
public function getArray()
{
return $this->_xmlToArray($this->_getSimpleXmlElement());
}

/**
* Get specified data from xml data
*
* @return string|array specified data.
*/
public function __get($name)
{
return $this->__call($name);
}

/**
* Get parameter (magic method call)
* Getting value from Xml data.
*
* @param $name key to get data from xml
* @param $argv no needs
* @return string|array specified key's value.
*/
public function __call($name, $argv = null)
{
$data = $this->getArray();
switch ($name) {
case 'region':
return $data['region'][0];
case 'code':
return $data['region']['code'];
case 'com':
case 'env':
case 'ind':
case 'sec':
case 'tra':
return $data['bases'][$name];
case 'rss':
return $this->getRss();
case 'xml':
return $this->getXml();
case 'embed':
return $this->getEmbedTag();
case 'json':
return $this->getJson();
case 'array':
return $this->getArray();
case 'flashvars':
return $this->getFlashVars();
default:
return (isset($data[$name])) ? $data[$name] : null;
}
}
}


Ok. Let's make API application.
For here, I want to make the url looks like this.

http://yoursite/?city=your_city_name

application/controllers/IndexController.php
<?php
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$city = $this->_getParam('city');
$height = $this->_getParam('height', null);
$width = $this->_getParam('width', null);
$showdetail = $this->_getParam('showdetail', false);
$s = new Hoge_Service_MyMiniCity($city);
echo $s->getEmbedTag($height, $width, $showdetail);
}
}


To get data in other way. You can get it as property.
echo $s->xml;
echo $s->json;
echo $s->array;
echo $s->embed; // but you can not set size or show detail setting.
echo $s->rss;

To show blog tool in your site, use javascript.
<script src="http://yoursite/path/to/application/?city=your_city_name" type="text/javascript"></script>


Don't have a time? Or feel bothering to make it?
Here is a sample.
http://api.f-pig.net/myminicity/?city=your_city_name
Try your city name insted of "your_city_name" :)

Any way, Zend Framework is nice and fun. I will try more.

Oops, I have to win the game with my co-workers what if I can lose my weight about 6kg until end of March, I will win!!
(weight 94.7kg BMI 34%)

Labels:

0 Comments:

Post a Comment

<< Home