基于 Yii 2.0,实现 RESTful 风格的 Web Service 服务的 API,请求参数中,仅某一参数支持多个参数值(即数组、列表输入)的数据填充、验证的实现
1、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,如图1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "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": "" } |
打印请求参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "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": "" } |
打印请求参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 的值为单个字符串时,其填充与验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | /** * 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 的值为数组时,其填充与验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | /** * 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 为字符串格式,响应失败,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "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": "" } |
1 2 3 4 | { "code": 40009, "message": "数据模型填充失败" } |
6、POST http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,请求参数 uuid 为数组格式,只存在1个键值对,其值错误,响应失败,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | { "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": "" } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" } |
1 | 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个键值对,其值皆错误,响应失败,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "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": "" } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" } |
1 2 | 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个值错误,响应失败,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "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": "" } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" } |
1 2 | 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个值正确,响应失败,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "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": "" } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" } |
1 2 | 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个键值对,其值皆正确,响应成功,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "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": "" } |
1 2 3 4 | { "code": 10000, "message": "发布文章类型:标准(普通、图文)的文章成功" } |
1 2 | 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、可以确定的结论:数组中存在几个键值对,则会执行同样数量的验证过程,不会因为某个值验证失败,后续的值就不再验证,暂时告一段落,后续优化,以实现当某个值验证失败后,后续的值就不再验证,而是直接响应失败才是。
近期评论