顶起先
没这方面经验 所以期待 其他人解答了 ;
不过 从以往资料来看 手机连接到你网站应该到一个唯一route上
比如 api/xml api/json api/html 控制器的actionXxx 处理不同格式的数据。 这些都应该是唯一访问点 你不要搞出多种来 比如 user/login user/signup 等…
然后 这些action中都只是 监听而已 需要架设server(RPC server) 比如:
class ApiController extends CController
{
public function actionRpc(){
// die(__METHOD__);
Yii::log("enter ". __METHOD__, CLogger::LEVEL_INFO);
Yii::import('application.vendors.json_rpc.jsonRPCServer');
$serviceProxy = YsService::instance();
jsonRPCServer::handle($serviceProxy)
or print 'no request';
Yii::log("end ". __METHOD__, CLogger::LEVEL_INFO);
die();
}
}
然后然后 有中心service来处理不同的请求 rpc 远程过程调用会跟本地类似的 这里需要一个映射表
格式如: apiName => apiServiceImplementCallable
键值应该是 api的外部调用的名字 比如 user_login user_signUP … 全部是字符串 但你要做某些前缀用来区分模块 防止 以后出现名字冲突 。
值 部分 绑定的是 php callable (你自己查 常见的 有 方法名, 类名::静态方法名 array($obj,‘methodName’)) 所以你要考虑如何将外部apiName 映射到本机上的函数 静态方法名 或者 对象的方法上 。 你搜索下 php RPC 应该可以找到相关库 很多的。
你最好 在提供一个service层 底层调用相应的Ar的功能; 比如 UserService 调用User 类来完成相关的业务方法 比如 siginIn 等对外暴露的服务方法。 但注意返回值 不能是ar了 转换成数组先 然后有好多库 可以辅助将 数组转换为xml或者json 格式 。难点在 复杂类型处理上 比如引用 关系型($photo->user )可能需要递归转换 … 还有考虑 分页问题 反正要考虑的太多了 。
我没这方面经验 所以只是我的想法而已 仅供参考。 下面给出我的 YsService 类的实现:
class YsService extends CApplicationComponent
{
/**
* @static
* @return YsService
*/
public static function instance()
{
if (!isset(Yii::app()->service)) {
Yii::app()->setComponents(array(
'service' => array(
'class' => __CLASS__,
// 'mode' => self::MODE_LOCAL,
),
), false);
}
return Yii::app()->service;
}
const MODE_JSON_RPC = 'json_rpc';
const MODE_XML_RPC = 'xml_rpc';
/**
* @see http://www.phprpc.org/zh_CN/
*/
const MODE_PHP_RPC = 'php_rpc';
const MODE_LOCAL = 'local';
/**
* @see http://code.google.com/p/fastcgirpc/
*/
const MODE_FAST_RPC = 'fast_rpc';
/**
* @static
* @param string $moduleId
* @param string $serviceName
* @param array $params
* @return mixed|void
*/
static public function call($moduleId = '', $serviceName = '', $params = array())
{
return self::instance()->callModuleService($moduleId,$serviceName,$params);
}
public $mode = self::MODE_LOCAL;
protected $modulePath = array();
public function callModuleService($moduleId = '', $serviceName = '', $params = array())
{
if ($this->mode = self::MODE_LOCAL) {
return $this->callLocalModuleService($moduleId, $serviceName, $params);
} elseif ($this->mode = self::MODE_JSON_RPC) {
return $this->callJsonRpcModuleService($moduleId,$serviceName,$params);
} else {
throw new CException("the {$this->model} is not supported yet");
}
}
/**
* @param string $moduleId
* @param string $serviceName
* @param array $params
* @return mixed
*/
protected function callLocalModuleService($moduleId = '', $serviceName = '', $params = array())
{
$modulePath = $this->getModulePath($moduleId);
if (($pos = strpos($serviceName, '.')) !== false) {
$serviceClassName = ucfirst(substr($serviceName, 0, $pos)) . "Service";
$serviceMethodName = substr($serviceName, $pos + 1);
} else {
$serviceClassName = ucfirst($moduleId) . "Service";
$serviceMethodName = $serviceName;
}
$servicePath = $modulePath . DIRECTORY_SEPARATOR . 'services' . DIRECTORY_SEPARATOR . "{$serviceClassName}.php";
require_once($servicePath);
$serviceObj = new $serviceClassName();
// setMode
if($serviceObj instanceof IModuleService){
$serviceObj->setProcessMode($this->mode);
}
return call_user_func_array(array($serviceObj, $serviceMethodName), $params);
}
/**
* @param $moduleId 目前只支持平面化module 不支持更深层次的module嵌套了
* @return string
* 如果通过moduleId 去找模块的路径 影响单元测试的 很麻烦
* 所以模块下的service 不要通过 module本身来提供 dolphin是module自身提供serviceXXX方法的
*/
protected function getModulePath($moduleId = '')
{
// return dirname(Yii::app()->getModule($moduleId)->getModulePath());
$modulePath = Yii::app()->getModulePath();
return $modulePath . DIRECTORY_SEPARATOR . $moduleId;
}
protected function callJsonRpcModuleService($moduleId = '', $serviceName = '', $params = array())
{
Yii::import('application.vendors.json_rpc.jsonRPCClient');
//$serviceRemoteProxy = new jsonRPCClient($this->createAbsoluteUrl('/api/rpc'),true);
$serviceRemoteProxy = new jsonRPCClient($this->createAbsoluteUrl('/api/rpc'));
try {
echo $serviceRemoteProxy->callModuleService($moduleId,$serviceName,$params);
} catch (Exception $e) {
echo nl2br($e->getMessage()).'<br />'."\n";
}
}
}