Monday, January 03, 2011

A happy new year 2011

A happy new year 2011

Oh my oh, in this first 3 days, I gained a lot. :p
Because the meals were so delicious!

So do you think what is the delicious meal?
It is a Japanese traditional meal called "Osechi"!


It looks colorful flowers isn't it?
Not only an appearance, but also the taste is nice. :)
If you have chance, come to Japan and try it!

Anyway, I wish you will be happy this year! :)

(weight 91.1kg BMI 33%)

Labels:

Wednesday, November 24, 2010

Try Zend Framework vol.13 "Dispatch Like Mojavi"

Do you remember "Mojavi" framework? :)
Once upon a time, there was a fantastic framework which is called "Mojavi".
If you were a PHP programmer, once you have probably heard that name.
But, it's not seems to be developed no longer.

So, tonight we look back old days and revive "Mojavi" as Zend dispacher! :)

Before talking about Mojavi, Let's talk about Ruby on Rails and frameworks around it.
After Ruby on Rails (RoR) was shown in the world, it became very famous and common as rapid web development tool.
It gives you cool architecture and the speed until making a product up.
Then many frameworks imitate to RoR, and they became similar to RoR.
And I think Zend Framework is also the one of them. :)

RoR style dispach is very simple and easy to understand, then keeps class and file less. When I saw that architechture first time, I was so impressed of its simpleness.

RoR style is very nice, but it is too hard to throw away Mojavi style.
I think Mojavi style is also simple and easy to identify the area of influence.

To know the diffrences between two styles, let's see both architechtures.
Comparing two of them, let's see Zend Frameworks' default structure.

There are "Model", "Controller" and "Action".

In Zend Framework, the standard dispatcher interprets "Module", "Controller" and "Action" from the executed url.
Actually it depends on the router, but for now , let's think about "Standard" dispatcher. ;)

OK, see the url below.
http://zf.f-pig.net/foo/bar/buz

There are three paths foo, bar and buz, it would be interpreted by dispatcher like this.
1.foo is "Module" and it is "Direcotry".
2.bar is "Controller" and it is "Class file".
3.buz is "Action" and it is "Method" of bar (controller).

And it looks like this.
application/
|~modules/
| |~foo/(module)
| | |~controllers/
| | | `~BarController.php (has "buz" method as action method.)

In BarController.php
class Foo_BarController extends Zend_Controller_Action
{
public function buzAction()
{
// this is buz action.
}
}

OK, that is Zend Framework style.

Then now, let's look back old days!!

From here I'm going to talk about Mojavi Framework style.
Mojavi interprets that url like this.
http://zf.f-pig.net/foo/bar/buz

1. foo is "Moduel" and it is "Directory".
2. bar is "Controller" it is also "Direcotry".
3. buz is "Action" and it is "Class file". It has a method to execute it self.

And it looks like this.
application/
|~modules/
| |~foo/(module)
| | |~controllers/
| | | `~Bar/(controller)
| | |   `-BuzAction.php(action having "execute" method.)

In BuzAction.php
class Foo_Bar_BuzAction extends Zend_Controller_Action
{
// this is action.

public function execute()
{
// this is an executive method of this action "class".
}
}


You may feel Mojavi style is too detailed style, and makes many class files and feel it messy.

But, this Mojavi style sometimes helps you.
There are some situations that Mojavi style can solve.

Case 1.
Let's think, you want to write some method which is for buzAction.
You probably write that method on BarController.
On the one hand, it's pretty normal, because there is no place to write that method,
on the other hand, you need to name that method to specify the aim that the method is for buzAction.

Case 2.
Zend_Controller_Action gives some useful methods like init, preDispatch and postDispatch.
But, these methods are on Controller, so every action method was called it would be called automatically.
Even if you don't want to call preDispatch when another action methods called, it would be called automatically.
Or you may need to write a "if statement" in these methods.

Case 3.
Imagine you are working with many coworkers whose skills are not same level as you.
They may touch a same class at the same project.
And you need to share the class file with them.
A coworker may use generic name even it only work for buzAction.
Once that code is released, it's pretty hard to refactor and release, isn't it?

Oops, I'm talking too much. :)
It's time to write Mojavi dispacher!

To make Mojavi style architecture, we need to make a new dispatcher!
Let's call it "Hoge_Controller_Dispatcher_MojaviLike".
Hoge_Controller_Dispatcher_MojaviLike
<?php
/**
* Hoge_Controller_Dispatcher_MojaviLike
* Dispatch like mojavi.
*/
class Hoge_Controller_Dispatcher_MojaviLike extends Zend_Controller_Dispatcher_Standard
{
/**
* Execute method name.
* @var string
*/
protected $_executeMethod = 'execute';

/**
* Set executable method name.
* @return void
*/
public function setExecuteMethod($name)
{
$this->_executeMethod = $name;
}

/**
* Get executable method name.
* @return executetable method name.
*/
public function getExecuteMethod()
{
return $this->_executeMethod;
}

/**
* Formats a string into a controller name.
* @param string $unformatted
* @return string
*/
public function formatControllerName($unformatted)
{
return ucfirst($this->_formatName($unformatted));
}

/**
* Formats a string into an action name.
* @param string $unformatted
* @return string
*/
public function formatActionName($unformatted)
{
return ucfirst(parent::formatActionName($unformatted));
}

/**
* Get action class name
*
* @param Zend_Controller_Request_Abstract $request
* @return string|false Returns class name on success
*/
public function getActionClass(Zend_Controller_Request_Abstract $request)
{
// controller info.
$controllerName = $request->getControllerName();
if (empty($controllerName)) {
if (!$this->getParam('useDefaultControllerAlways')) {
return false;
}
$controllerName = $this->getDefaultControllerName();
$request->setControllerName($controllerName);
}
$controllerName = $this->formatControllerName($controllerName);


// action info.
$actionName = $request->getActionName();
if (empty($actionName)) {
if (!$this->getParam('useDefaultActionAlways')) {
return false;
}
$actionName = $this->getDefaultAction();
$request->setActionName($actionName);
}
$actionName = $this->formatActionName($actionName);

// build class name.
$className = $controllerName . $this->getPathDelimiter() . $actionName;

$controllerDirs = $this->getControllerDirectory();
$module = $request->getModuleName();
if ($this->isValidModule($module)) {
$this->_curModule    = $module;
$this->_curDirectory = $controllerDirs[$module];
} elseif ($this->isValidModule($this->_defaultModule)) {
$request->setModuleName($this->_defaultModule);
$this->_curModule    = $this->_defaultModule;
$this->_curDirectory = $controllerDirs[$this->_defaultModule];
} else {
require_once 'Zend/Controller/Exception.php';
throw new Zend_Controller_Exception('No default module defined for this application');
}

return $className;
}

/**
* Returns TRUE if the Zend_Controller_Request_Abstract object can be
* @param Zend_Controller_Request_Abstract $action
* @return boolean
*/
public function isDispatchable(Zend_Controller_Request_Abstract $request)
{
$className = $this->getActionClass($request);
if (!$className) {
return false;
}
$finalClass  = $className;
if (($this->_defaultModule != $this->_curModule)
|| $this->getParam('prefixDefaultModule'))
{
$finalClass = $this->formatClassName($this->_curModule, $className);
}
if (class_exists($finalClass, false)) {
return true;
}

$fileSpec    = $this->classToFilename($className);
$dispatchDir = $this->getDispatchDirectory();
$test        = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec;
return Zend_Loader::isReadable($test);
}

/**
* Dispatch to a controller/action
* @param Zend_Controller_Request_Abstract $request
* @param Zend_Controller_Response_Abstract $response
* @return void
* @throws Zend_Controller_Dispatcher_Exception
*/
public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response)
{
$this->setResponse($response);

/**
* Get action class
*/
if (!$this->isDispatchable($request)) {
$action = $request->getControllerName();
if (!$this->getParam('useDefaultActionAlways') && !empty($action)) {
require_once 'Zend/Controller/Dispatcher/Exception.php';
throw new Zend_Controller_Dispatcher_Exception(
'Invalid controller/action specified (' .
$request->getControllerName() . '/' . $request->getActionName() . ')');
}
$className = $this->getDefaultActionClass($request);
} else {
$className = $this->getActionClass($request);
if (!$className) {
$className = $this->getDefaultActionClass($request);
}
}

/**
* Load the action class file
*/
$className = $this->loadClass($className);

$action = new $className($request, $this->getResponse(), $this->getParams());
if (!($action instanceof Zend_Controller_Action_Interface) &&
!($action instanceof Zend_Controller_Action)) {
require_once 'Zend/Controller/Dispatcher/Exception.php';
throw new Zend_Controller_Dispatcher_Exception(
'Action "' . $className . '" is not an instance of
Zend_Controller_Action_Interface'
);
}

/**
* Retrieve the execution name
*/
$execute = $this->getExecuteMethod();

$request->setDispatched(true);

// by default, buffer output
$disableOb = $this->getParam('disableOutputBuffering');
$obLevel   = ob_get_level();
if (empty($disableOb)) {
ob_start();
}

try {
$action->dispatch($execute);
} catch (Exception $e) {
// Clean output buffer on error
$curObLevel = ob_get_level();
if ($curObLevel > $obLevel) {
do {
ob_get_clean();
$curObLevel = ob_get_level();
} while ($curObLevel > $obLevel);
}
throw $e;
}

if (empty($disableOb)) {
$content = ob_get_clean();
$response->appendBody($content);
}

// Destroy the page controller instance and reflection objects
$action = null;
}

/**
* Retrieve default action class
*
* @param Zend_Controller_Request_Abstract $request
* @return string
*/
public function getDefaultActionClass(Zend_Controller_Request_Abstract $request)
{
$controller = $this->getDefaultControllerName();
$defaultController = $this->formatControllerName($controller);

$action = $this->getDefaultAction();
$defaultAction = $this->formatControllerName($action);

$default = $defaultController . $this->getPathDelimiter() . $defaultAction;

$request->setControllerName($controller)
->setActionName($action);

$module              = $request->getModuleName();
$controllerDirs      = $this->getControllerDirectory();
$this->_curModule    = $this->_defaultModule;
$this->_curDirectory = $controllerDirs[$this->_defaultModule];

if ($this->isValidModule($module)) {
$found = false;
if (class_exists($default, false)) {
$found = true;
} else {
$moduleDir = $controllerDirs[$module];
$fileSpec  = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default);
if (Zend_Loader::isReadable($fileSpec)) {
$found = true;
$this->_curDirectory = $moduleDir;
}
}
if ($found) {
$request->setModuleName($module);
$this->_curModule = $this->formatModuleName($module);
}
} else {
$request->setModuleName($this->_defaultModule);
}

return $default;
}


To switch dispatcher.
$frontController = Zend_Controller_Front::getInstance();
$frontController->setDispatcher(new Hoge_Controller_Dispatcher_MojaviLike())


With this Mojavi dispacher, Controller class will be Action class.
It looks like this.

application/modules/foo/controllers/Bar/BuzAction.php
<?php
class Foo_Bar_BuzAction extends Zend_Controller_Action
{
/** 
* init
*/
public function init()
{   
$this->view->class = '"' . __CLASS__ . '" class';
$this->view->init = '"' . __FUNCTION__ . '" is called';
}   

/** 
* preDispatch
*/
public function preDispatch()
{   
$this->view->preDispatch = '"' . __FUNCTION__ . '" is called';
}   

/** 
* postDispatch
*/
public function postDispatch()
{   
$this->view->postDispatch = '"' . __FUNCTION__ . '" is called';
}   

/** 
* execute this class. 
*/
public function execute()
{   
$this->view->execute = '"' . __FUNCTION__ . '" is called';
}   
}


How about templates?
There is no need to change anything!

To show registered view values above template looks like this.

application/modules/foo/views/scripts/bar/buz.phtml
<b>Mojavi Like</b>
<? foreach ($this as $key =>  $prop): ?>
<?= $prop ?><br />
<? endforeach ?>
But, I also think Zend style is pretty nice and enough. :)
The Controller and Action method should be as small as they can.
The logic should be written in Model class?! Actually I'm not sure if it should be. :p

But, please don't forget, in the real world,
it's pretty hard that all coworkers write source code beautifully and same style. : <

In these case, "Mojavi" style might help you.

At last, thank Mojavi to appeared in this world. And good bye!! :)

(weight 89.6kg BMI 32%)

Labels:

Friday, January 01, 2010

A happy new year 2010

A happy new year 2010!
I wish you will be happy this year! :)

(weight 94.6kg BMI 34%)

Labels:

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:

Sunday, January 04, 2009

A Happy New Year 2009

A happy new year 2009!

Looking back 2008, I didn't write entry so much. :P
I will write it this year!!
And this is the first entry in 2009.

Anyway, I hope everyone happy this year! :)

oops, I ate new year meals too much. :<
(weight 93.3kg BMI 33%)

Labels:

Tuesday, November 18, 2008

Zend Framework 1.7 is released!!

Yahoooooooooooooooooooooooooooooooooooooo!!

Zend Framework 1.7 is released !

Zend_AMF will become a rainbow bridge to the Actionscripters!
ZendX_JQuery will become a lighthouse for the Javascripters!

Any way, I restarted to use Zend Framework for my new project :)
And so happy to forget how fatty I am!!
(weight I don't kg BMI care%)

Labels:

Wednesday, September 03, 2008

Zend Framework 1.6 is released!!

Yahoooooooooooooooooooooooooooooooooooooo!!

Zend Framework 1.6 is released !
With dojo ?? Oh OKay.
It has been enhanced a lot while I haven't checked. :)

Any way, it's been a long time since I worte the last entry :P
And so happy to forget how fatty I am!!
(weight I don't kg BMI care%)

Labels: