Zend_Server

Let’s take a quick look at something that’s kind of neat in Zend Framework. I’ve been doing some work with Adobe on some articles and one of them was on working with mobile clients with Flash. Well, me being the masochist I did more. What I did was write an example that worked as a full website, an Ajax website, a Flash service and an XML-RPC service.

Setting the Stage

First I started with a Zend_Db row instance and it’s corresponding table instance.

Zend_Server

Now for the fun part. Notice serviceAction()? That’s where the Zend_Server_* stuff comes in. In a plugin, which I will show you in a bit, I attached an instance of Zend_Server_Interface. Then in the controller I simple told it to do its thing, with the exception of handing the Service Mapping Description for JSON-RPC ($smd). That’s it. Because Zend_Json_Server, Zend_XmlRpc_Server and Zend_Amf_Server all implement the Zend_Server_Interface interface that’s all I needed to do.

But since everything is going to one place you need to do a bunch of freaky logic to get the right one, right? Nope. It’s actually quite easy. What I did was create a plugin that detected the request type, instantiated the required server instance and attached it to the request after setting the request object to execute the serviceAction() method instead of the requested one. In other words, you could send your request to /34gas/q43ar/13/asdfg/as and it would still go to the serviceAction() method. Here’s the code

class Ctx_Controller_Plugin_ServicePlugin extends Zend_Controller_Plugin_Abstract
{publicfunction routeShutdown ( Zend_Controller_Request_Abstract $request){$serviceHandler=null;if($request->isXmlHttpRequest()&&$request->isPost()){$serviceHandler=new Zend_Json_Server();$serviceHandler->getServiceMap()->setDojoCompatible(true);}elseif($request->isFlashRequest()){$serviceHandler=new Zend_Amf_Server();/* Note: This may be different depending on the SAPI you are using */}elseif(strpos($request->CONTENT_TYPE,'text/xml')===0){$serviceHandler=new Zend_XmlRpc_Server('http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']);}elseif($request->isXmlHttpRequest()){$serviceHandler=new Zend_Json_Server();$smd=$serviceHandler->getServiceMap();$smd->setDojoCompatible(true);$request->setParam('smd',$smd);$view=new Zend_View();$serviceHandler->setTarget($view->url())->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);}if($serviceHandler){foreach(glob(APPLICATION_PATH.'/mappers/*.php')as$dir){$name=substr(basename($dir),0,-4);$class='Mapper_'.$name;$serviceHandler->setClass($class,$name);}$request->setParam('serviceHandler',$serviceHandler);$request->setControllerName('index');$request->setActionName('service');}}}

Looks like a lot, right? Actually there’s not much there. Here’s the logic flow.

Is it an XMLHTTP Request and is it a POST? Create the Json server

Is it an AMF request? Create the AMF server

Is it an XmlRpc request? Create the XmlRpc server

Is it an XMLHTTP Request and is it a GET? Create the Service Map (for JSON-RPC 2.0)

If a service handler has been created add all of the application’s mappers, attach the service handler to the request and redirect to the service action.

And with that you have an application that can serve content for multiple different types of service with almost no effort on your part. At least.. if you copy and paste this code.