在接口類檔案裡,可以設定某個接口方法的請求參數相關過濾條件,然後直接用$this調用請求參數,如下:
<?php
namespace App\Api\Home;
use PhalApi\Api;
/**
* 雜項
*/
class SiteInfo extends Common {
public function getRules() {
return array(
'advice' => array(
'content' => array('name' => 'content', 'require' => true, 'type' => 'string','des'=>'回報内容'),
'contact' => array('name' => 'contact', 'require' => true, 'type' => 'string','des'=>'聯系電話'),
'imageList' => array('name' => 'imageList', 'require' => false, 'type' => 'string','des'=>'圖檔'),
)
);
}
SiteInfo的advice接口有三個請求參數,其中content和contact都是必傳的.由于所有的接口類都繼承Api是以,我們去看一個請求來時,是怎麼在運作請求方法時,先過濾相關參數是否合法.
PhalApi\Api類的初始化方法如下:
/**
* 初始化
*
* 主要完成的初始化工作有:
* - 1、[必須]按參數規則解析生成接口參數
* - 2、[可選]過濾器調用,如:簽名驗證
* - 3、[可選]使用者身份驗證
*
* @uses Api::createMemberValue()
* @uses Api::filterCheck()
* @uses Api::userCheck()
* @return null
*/
public function init() {
$this->createMemberValue();
$this->filterCheck();
$this->userCheck();
}
第一步$this->createMemberValue();就是對請求參數進行檢查,我們看函數内容:
/**
* 按參數規則解析生成接口參數
*
* 根據配置的參數規則,解析過濾,并将接口參數存放于類成員變量
*
* @uses Api::getApiRules()
*/
protected function createMemberValue() {
foreach ($this->getApiRules() as $key => $rule) {
$this->$key = DI()->request->getByRule($rule);
}
}
/**
* 取接口參數規則
*
* 主要包括有:
* - 1、[固定]系統級的service參數
* - 2、應用級統一接口參數規則,在app.apiCommonRules中配置
* - 3、接口級通常參數規則,在子類的*中配置
* - 4、接口級目前操作參數規則
*
* <b>當規則有沖突時,以後面為準。另外,被請求的函數名和配置的下标都轉成小寫再進行比對。</b>
*
* @uses 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)) {
// fixed issue #22
if ($this->isServiceWhitelist()) {
foreach ($apiCommonRules as &$ruleRef) {
$ruleRef['require'] = false;
}
}
$rules = array_merge($apiCommonRules, $rules);
}
return $rules;
}
getApiRules方法主要是做了下面幾件事:
1.先調用請求類檔案裡的getRules方法擷取具體類檔案的使用者參數規則配置.然後檢索出目前請求的具體方法的參數規則。
2.phalapi的參數配置分全局和具體,全局可以在配置檔案裡通過 apiCommonRules配置,類全局是通過在本類的getRules裡通過*配置:
/**
* 應用接口層的統一參數
*/
'apiCommonRules' => array(
//簽名
'sign' => array(
'name' => 'sign', 'require' => true,
),
//用戶端App版本号,預設為:1.4.0
'version' => array(
'name' => 'version', 'default' => '1.4.0',
),
),
類全局如下:
'*' => array(
'code' => array('name' => 'code', 'require' => true, 'min' => 4, 'max' => 4),
),
是以,我們這裡取到具體配置後,還要分别取全局參數配置以及類全局配置,然後通過array_merge組裝成一個數組。
擷取所有配置後,我們再來看它是怎麼處理的:
DI()->request->getByRule($rule)方法如下:
/**
* 根據規則擷取參數
* 根據提供的參數規則,進行參數建立工作,并傳回錯誤資訊
*
* @param $rule array('name' => '', 'type' => '', 'defalt' => ...) 參數規則
*
* @return mixed
* @throws BadRequestException
* @throws InternalServerErrorException
*/
public function getByRule($rule) {
$rs = NULL;
if (!isset($rule['name'])) {
throw new InternalServerErrorException(T('miss name for rule'));
}
// 擷取接口參數級别的資料集
$data = !empty($rule['source']) && substr(php_sapi_name(), 0, 3) != 'cli'
? $this->getDataBySource($rule['source'])
: $this->data;
$rs = Parser::format($rule['name'], $rule, $data);
if ($rs === NULL && (isset($rule['require']) && $rule['require'])) {
// 支援自定義友好的錯誤提示資訊,并支援i18n國際翻譯
$message = isset($rule['message'])
? T($rule['message'])
: T('{name} require, but miss', array('name' => $rule['name']));
throw new BadRequestException($message);
}
return $rs;
}
看來具體的驗證在Parser::format這個方法裡了.
主要實作是下面方法:
/**
* 根據範圍進行控制
*/
protected function filterByRange($value, $rule) {
$this->filterRangeMinLessThanOrEqualsMax($rule);
$this->filterRangeCheckMin($value, $rule);
$this->filterRangeCheckMax($value, $rule);
return $value;
}
protected function filterRangeMinLessThanOrEqualsMax($rule) {
if (isset($rule['min']) && isset($rule['max']) && $rule['min'] > $rule['max']) {
throw new InternalServerErrorException(
\PhalApi\T('min should <= max, but now {name} min = {min} and max = {max}',
array('name' => $rule['name'], 'min' => $rule['min'], 'max' => $rule['max']))
);
}
}
protected function filterRangeCheckMin($value, $rule) {
if (isset($rule['min']) && $value < $rule['min']) {
$message = isset($rule['message'])
? \PhalApi\T($rule['message'])
: \PhalApi\T('{name} should >= {min}, but now {name} = {value}',
array('name' => $rule['name'], 'min' => $rule['min'], 'value' => $value));
throw new BadRequestException($message);
}
}
protected function filterRangeCheckMax($value, $rule) {
if (isset($rule['max']) && $value > $rule['max']) {
$message = isset($rule['message'])
? \PhalApi\T($rule['message'])
: \PhalApi\T('{name} should <= {max}, but now {name} = {value}',
array('name' => $rule['name'], 'max' => $rule['max'], 'value' => $value));
throw new BadRequestException($message);
}
}
比如目前參數是整形的話,規則裡設定了min,max,屬性就通過這裡來判斷.值得注意的是,所有參數規則解析
是統一在formatAllType裡處理
/**
* 統一分發處理
* @param string $type 類型
* @param string $value 值
* @param array $rule 規則配置
* @return mixed
*/
protected static function formatAllType($type, $value, $rule) {
$diKey = '_formatter' . ucfirst($type);
$diDefautl = '\\PhalApi\\Request\\Formatter\\' . ucfirst($type) . 'Formatter';
$formatter = \PhalApi\DI()->get($diKey, $diDefautl);
if (!($formatter instanceof Formatter)) {
throw new InternalServerErrorException(
//\PhalApi\T('invalid type: {type} for rule: {name}', array('type' => $type, 'name' => $rule['name']))
\app\getMsg('074',"401", array('type' => $type, 'name' => $rule['name']))
);
}
return $formatter->parse($value, $rule);
}
formatAllType裡我們可以看到,這個方法裡根據參數類型,調用不同參數類型的處理類來處理對應參數.
總結:
我通路add接口,基類Api在實際方法前先進行參數檢查。比如在getRules裡設定參數為整形,我就調用Parse目錄裡的整形檢查類來進行相關檢查.