基于 Yii 2.0,实现 RESTful 风格的 Web Service 服务的 API,请求参数中,仅某一参数支持多个参数值(即数组、列表输入)的数据填充、验证的实现
1、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,如图1
{ "uuid": "e88e79faad9011e8a14554ee75d2ebc1", "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
打印请求参数:
Array ( [uuid] => e88e79faad9011e8a14554ee75d2ebc1 [article_type_code] => standard [article_category_id] => 1 [title] => 标题 - 20180904 - 1 [author] => 作者 - 20180904 - 1 [source] => spider [source_user_id] => 1 [source_article_id] => 1 [content] => 文章内容 - 20180904 - 1 [cover_pic] => /upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif [cover_type] => 1 [tag] => [apply] => 0 [original_platform] => 0 [original_url] => [original_author] => [group_id] => 015ce30b116ce86058fa6ab4fea4ac63 )
2、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,如图2
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc1", "9f359272b00e11e8875654ee75d2ebc1" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
打印请求参数:
Array ( [uuid] => Array ( [0] => e88e79faad9011e8a14554ee75d2ebc1 [1] => 9f359272b00e11e8875654ee75d2ebc1 ) [article_type_code] => standard [article_category_id] => 1 [title] => 标题 - 20180904 - 1 [author] => 作者 - 20180904 - 1 [source] => spider [source_user_id] => 1 [source_article_id] => 1 [content] => 文章内容 - 20180904 - 1 [cover_pic] => /upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif [cover_type] => 1 [tag] => [apply] => 0 [original_platform] => 0 [original_url] => [original_author] => [group_id] => 015ce30b116ce86058fa6ab4fea4ac63 )
3、查看 \qq\rests\article\CreateAction.php,当 uuid 的值为单个字符串时,其填充与验证代码
/** * Creates a new model. * @return \yii\db\ActiveRecordInterface the model newly created * @throws ServerErrorHttpException if there is any error when creating the model */ public function run() { if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id); } $requestParams = Yii::$app->getRequest()->getBodyParams(); /* 判断请求体参数中租户ID是否存在 */ if (!isset($requestParams['group_id'])) { $requestParams = ArrayHelper::merge($requestParams, ['group_id' => Yii::$app->params['groupId']]); } /* 标准(普通、图文)的文章发布参数 */ $qqArticleStandardCreateParam = new QqArticleStandardCreateParam(); // 把请求数据填充到模型中 if (!$qqArticleStandardCreateParam->load($requestParams, '')) { return ['code' => 40009, 'message' => Yii::t('error', '40009')]; } // 验证模型 if (!$qqArticleStandardCreateParam->validate()) { $qqArticleStandardCreateParamResult = self::handleValidateError($qqArticleStandardCreateParam); if ($qqArticleStandardCreateParamResult['status'] === false) { return ['code' => $qqArticleStandardCreateParamResult['code'], 'message' => $qqArticleStandardCreateParamResult['message']]; } } /* 基于文章类型代码定义场景 */ $this->scenario = 'qq_article_' . $qqArticleStandardCreateParam->article_type_code . '_create'; /* 实例化多个模型 */ // 企鹅号的第三方服务平台应用的企鹅媒体用户 $qqTpAppPenguin = new QqTpAppPenguin([ 'scenario' => $this->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams[$qqTpAppPenguin->formName()]['uuid'] = $qqArticleStandardCreateParam->uuid; $qqTpAppPenguinResult = self::handleLoadAndValidate($qqTpAppPenguin, $requestParams); if ($qqTpAppPenguinResult['status'] === false) { return ['code' => $qqTpAppPenguinResult['code'], 'message' => $qqTpAppPenguinResult['message']]; } } /** * 处理模型填充与验证 * @param object $model 模型 * @param array $requestParams 请求参数 * @return array * 格式如下: * * [ * 'status' => true, // 成功 * ] * * [ * 'status' => false, // 失败 * 'code' => 20004, // 返回码 * 'message' => '数据验证失败:企鹅号ID(UUID)是无效的。', // 说明 * ] * * @throws ServerErrorHttpException */ public static function handleLoadAndValidate($model, $requestParams) { // 把请求数据填充到模型中 if (!$model->load($requestParams)) { return ['status' => false, 'code' => 40009, 'message' => Yii::t('error', '40009')]; } // 验证模型 if (!$model->validate()) { return self::handleValidateError($model); } return ['status' => true]; } /** * 处理模型错误 * @param object $model 模型 * @return array * 格式如下: * * [ * 'status' => false, // 失败 * 'code' => 20004, // 返回码 * 'message' => '数据验证失败:代码是无效的。', // 说明 * ] * * @throws ServerErrorHttpException */ public static function handleValidateError($model) { if ($model->hasErrors()) { $response = Yii::$app->getResponse(); $response->setStatusCode(422, 'Data Validation Failed.'); foreach ($model->getFirstErrors() as $message) { $firstErrors = $message; break; } return ['status' => false, 'code' => 20004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20004'), ['firstErrors' => $firstErrors]))]; } elseif (!$model->hasErrors()) { throw new ServerErrorHttpException('Failed to create the object for unknown reason.'); } }
4、参考网址:https://www.yiiframework.com/doc/guide/2.0/zh-cn/input-tabular-input ,编辑 \qq\rests\article\CreateAction.php,当 uuid 的值为数组时,其填充与验证代码
/** * Creates a new model. * @return \yii\db\ActiveRecordInterface the model newly created * @throws ServerErrorHttpException if there is any error when creating the model */ public function run() { if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id); } $requestParams = Yii::$app->getRequest()->getBodyParams(); /* 判断请求体参数中租户ID是否存在 */ if (!isset($requestParams['group_id'])) { $requestParams = ArrayHelper::merge($requestParams, ['group_id' => Yii::$app->params['groupId']]); } /* 标准(普通、图文)的文章发布参数 */ $qqArticleStandardCreateParam = new QqArticleStandardCreateParam(); // 把请求数据填充到模型中 if (!$qqArticleStandardCreateParam->load($requestParams, '')) { return ['code' => 40009, 'message' => Yii::t('error', '40009')]; } // 验证模型 if (!$qqArticleStandardCreateParam->validate()) { $qqArticleStandardCreateParamResult = self::handleValidateError($qqArticleStandardCreateParam); if ($qqArticleStandardCreateParamResult['status'] === false) { return ['code' => $qqArticleStandardCreateParamResult['code'], 'message' => $qqArticleStandardCreateParamResult['message']]; } } /* 基于文章类型代码定义场景 */ $this->scenario = 'qq_article_' . $qqArticleStandardCreateParam->article_type_code . '_create'; /* 实例化多个模型 */ // 企鹅号的第三方服务平台应用的企鹅媒体用户 if (!is_array($requestParams['uuid'])) { return ['code' => 40009, 'message' => Yii::t('error', '40009')]; } $count = count($requestParams['uuid']); // 创建一个初始的 $qqTpAppPenguins 数组包含一个默认的模型 $qqTpAppPenguins = [new QqTpAppPenguin([ 'scenario' => $this->scenario, ])]; for($i = 1; $i < $count; $i++) { $qqTpAppPenguins[] = new QqTpAppPenguin([ 'scenario' => $this->scenario, ]); } foreach ($requestParams['uuid'] as $key => $uuid) { // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams[$qqTpAppPenguins[0]->formName()][$key]['uuid'] = $uuid; } // 批量填充模型属性 if (!Model::loadMultiple($qqTpAppPenguins, $requestParams, $qqTpAppPenguins[0]->formName())) { return ['code' => 40009, 'message' => Yii::t('error', '40009')]; } // 批量验证模型 if (!Model::validateMultiple($qqTpAppPenguins)) { $qqTpAppPenguinsResult = self::handleValidateMultipleError($qqTpAppPenguins); if ($qqTpAppPenguinsResult['status'] === false) { return ['code' => $qqTpAppPenguinsResult['code'], 'message' => $qqTpAppPenguinsResult['message']]; } } } /** * 处理模型填充与验证 * @param object $model 模型 * @param array $requestParams 请求参数 * @return array * 格式如下: * * [ * 'status' => true, // 成功 * ] * * [ * 'status' => false, // 失败 * 'code' => 20004, // 返回码 * 'message' => '数据验证失败:企鹅号ID(UUID)是无效的。', // 说明 * ] * * @throws ServerErrorHttpException */ public static function handleLoadAndValidate($model, $requestParams) { // 把请求数据填充到模型中 if (!$model->load($requestParams)) { return ['status' => false, 'code' => 40009, 'message' => Yii::t('error', '40009')]; } // 验证模型 if (!$model->validate()) { return self::handleValidateError($model); } return ['status' => true]; } /** * 处理模型错误 * @param object $model 模型 * @return array * 格式如下: * * [ * 'status' => false, // 失败 * 'code' => 20004, // 返回码 * 'message' => '数据验证失败:代码是无效的。', // 说明 * ] * * @throws ServerErrorHttpException */ public static function handleValidateError($model) { if ($model->hasErrors()) { $response = Yii::$app->getResponse(); $response->setStatusCode(422, 'Data Validation Failed.'); foreach ($model->getFirstErrors() as $message) { $firstErrors = $message; break; } return ['status' => false, 'code' => 20004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20004'), ['firstErrors' => $firstErrors]))]; } elseif (!$model->hasErrors()) { throw new ServerErrorHttpException('Failed to create the object for unknown reason.'); } } /** * 处理模型错误 * @param array $models 模型列表 * @return array * 格式如下: * * [ * 'status' => false, // 失败 * 'code' => 20004, // 返回码 * 'message' => '数据验证失败:代码是无效的。', // 说明 * ] * * @throws ServerErrorHttpException */ public static function handleValidateMultipleError($models) { foreach ($models as $model) { if ($model->hasErrors()) { $response = Yii::$app->getResponse(); $response->setStatusCode(422, 'Data Validation Failed.'); foreach ($model->getFirstErrors() as $message) { $firstErrors = $message; break; } return ['status' => false, 'code' => 20004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20004'), ['firstErrors' => $firstErrors]))]; } } throw new ServerErrorHttpException('Failed to create the object for unknown reason.'); }
5、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为字符串格式,响应失败,符合预期
{ "uuid": "e88e79faad9011e8a14554ee75d2ebc1", "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 40009, "message": "数据模型填充失败" }
6、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,只存在1个键值对,其值错误,响应失败,符合预期
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc10" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" }
SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='e88e79faad9011e8a14554ee75d2ebc10') AND (`status`=1))
7、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,存在2个键值对,其值皆错误,响应失败,符合预期
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc15", "9f359272b00e11e8875654ee75d2ebc16" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" }
SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='e88e79faad9011e8a14554ee75d2ebc15') AND (`status`=1)) SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='9f359272b00e11e8875654ee75d2ebc16') AND (`status`=1))
8、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,存在2个键值对,第1个值正确,第2个值错误,响应失败,符合预期
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc1", "9f359272b00e11e8875654ee75d2ebc16" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" }
SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='e88e79faad9011e8a14554ee75d2ebc1') AND (`status`=1)) SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='9f359272b00e11e8875654ee75d2ebc16') AND (`status`=1))
9、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,存在2个键值对,第1个值错误,第2个值正确,响应失败,符合预期
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc13", "9f359272b00e11e8875654ee75d2ebc1" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" }
SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='e88e79faad9011e8a14554ee75d2ebc13') AND (`status`=1)) SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='9f359272b00e11e8875654ee75d2ebc1') AND (`status`=1))
10、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,存在2个键值对,其值皆正确,响应成功,符合预期
{ "uuid": [ "e88e79faad9011e8a14554ee75d2ebc1", "9f359272b00e11e8875654ee75d2ebc1" ], "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180904 - 1", "author": "作者 - 20180904 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180904 - 1", "cover_pic": "/upload/Image/mrtp/2018/08/30/1_8a2fa998c0624c0ebee6eb72c5434e7a.gif", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" }
{ "code": 10000, "message": "发布文章类型:标准(普通、图文)的文章成功" }
SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='e88e79faad9011e8a14554ee75d2ebc1') AND (`status`=1)) SELECT EXISTS(SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`='9f359272b00e11e8875654ee75d2ebc1') AND (`status`=1))
11、可以确定的结论:数组中存在几个键值对,则会执行同样数量的验证过程,不会因为某个值验证失败,后续的值就不再验证,暂时告一段落,后续优化,以实现当某个值验证失败后,后续的值就不再验证,而是直接响应失败才是。
近期评论