通常地,可以这样继承:
* ``` * class Api_Demo extends PhalApi_Api { * * public function getRules() { * return array( * // ... * ); * } * * public function doSth() { * $rs = array(); * * // ... * * return $rs; * } * } ``` * * @property mixed $whatever 接口参数 * @package PhalApi\Api * @license http://www.phalapi.net/license GPL 协议 GPL 协议 * @link http://www.phalapi.net/ * @author dogstar 2014-10-02 */ class PhalApi_Api { /** * 设置规则解析后的接口参数 * @param string $name 接口参数名字 * @param mixed $value 接口参数解析后的值 */ public function __set($name, $value) { $this->$name = $value; } /** * 获取规则解析后的接口参数 * @param string $name 接口参数名字 * @throws PhalApi_Exception_InternalServerError 获取未设置的接口参数时,返回500 * @return mixed */ public function __get($name) { if(!isset($this->$name) || empty($name)) { throw new PhalApi_Exception_InternalServerError( T('PhalApi_Api::${name} undefined', array('name' => $name)) ); } return $this->$name; } /** * 初始化 * * 主要完成的初始化工作有: * - 1、[必须]按参数规则解析生成接口参数 * - 2、[可选]过滤器调用,如:签名验证 * - 3、[可选]用户身份验证 * * @uses PhalApi_Api::createMemberValue() * @uses PhalApi_Api::filterCheck() * @uses PhalApi_Api::userCheck() * @return null */ public function init() { $this->createMemberValue(); $this->filterCheck(); $this->userCheck(); } /** * 按参数规则解析生成接口参数 * * 根据配置的参数规则,解析过滤,并将接口参数存放于类成员变量 * * @uses PhalApi_Api::getApiRules() */ protected function createMemberValue() { foreach ($this->getApiRules() as $key => $rule) { $this->$key = DI()->request->getByRule($rule); } } /** * 取接口参数规则 * * 主要包括有: * - 1、[固定]系统级的service参数 * - 2、应用级统一接口参数规则,在app.apiCommonRules中配置 * - 3、接口级通常参数规则,在子类的*中配置 * - 4、接口级当前操作参数规则 * * 当规则有冲突时,以后面为准。另外,被请求的函数名和配置的下标都转成小写再进行匹配。 * * @uses PhalApi_Api::getRules() * @return array */ public function getApiRules() { $rules = array(); $allRules = $this->getRules(); if (!is_array($allRules)) { $allRules = array(); } $allRules = array_change_key_case($allRules, CASE_LOWER); $action = strtolower(DI()->request->getServiceAction()); if (isset($allRules[$action]) && is_array($allRules[$action])) { $rules = $allRules[$action]; } if (isset($allRules['*'])) { $rules = array_merge($allRules['*'], $rules); } $apiCommonRules = DI()->config->get('app.apiCommonRules', array()); if (!empty($apiCommonRules) && is_array($apiCommonRules)) { $rules = array_merge($apiCommonRules, $rules); } return $rules; } /** * 获取参数设置的规则 * * 可由开发人员根据需要重载 * * @return array */ public function getRules() { return array(); } /** * 过滤器调用 * * 可由开发人员根据需要重载,以实现项目拦截处理,需要: * - 1、实现PhalApi_Filter::check()接口 * - 2、注册的过滤器到DI()->filter * *
以下是一个简单的示例:
``` * class My_Filter implements PhalApi_Filter { * * public function check() { * //TODO * } * } * * * //在初始化文件 init.php 中注册过滤器 * DI()->filter = 'My_Filter'; ``` * * @see PhalApi_Filter::check() * @throws PhalApi_Exception_BadRequest 当验证失败时,请抛出此异常,以返回400 */ protected function filterCheck() { // 过滤服务白名单 if ($this->isServiceWhitelist()) { return; } $filter = DI()->get('filter', 'PhalApi_Filter_None'); if (isset($filter)) { if (!($filter instanceof PhalApi_Filter)) { throw new PhalApi_Exception_InternalServerError( T('DI()->filter should be instanceof PhalApi_Filter')); } $filter->check(); } } /** * 用户身份验证 * * 可由开发人员根据需要重载,此通用操作一般可以使用委托或者放置在应用接口基类 * * @throws PhalApi_Exception_BadRequest 当验证失败时,请抛出此异常,以返回400 */ protected function userCheck() { } /** * 是否为白名单的服务 * * @return boolean */ protected function isServiceWhitelist() { $api = DI()->request->getServiceApi(); $action = DI()->request->getServiceAction(); $serviceWhitelist = DI()->config->get('app.service_whitelist', array()); foreach ($serviceWhitelist as $item) { $cfgArr = explode('.', $item); if (count($cfgArr) < 2) { continue; } // 短路返回 if ($this->equalOrIngore($api, $cfgArr[0]) && $this->equalOrIngore($action, $cfgArr[1])) { return TRUE; } } return FALSE; } /** * 相等或忽略 * * @param string $str 等判断的字符串 * @param string $cfg 规则配置,*号表示通配 * @return boolean */ protected function equalOrIngore($str, $cfg) { return strcasecmp($str, $cfg) == 0 || $cfg == '*'; } }