基于 yiisoft/yii2-app-advanced,实现 RESTful 风格的 Web Service 服务的 API,请求参数为多模型时,数据填充、验证的实现
1、参考网址:https://www.yiiframework.com/doc/guide/2.0/zh-cn/input-multiple-models ,其用于网页表单是合适的,不过 API 应用的请求参数一般并未添加表单名称(尤其是单个模型输入时),因此,不太合适,例:表名为 article_type,字段名为 code,那么请求参数名为 article_type_code,而不是:ArticleType[‘code’],网页表单如图1
2、现在模型数量为7个,分别为:qq_tp_app_penguin(企鹅号的第三方服务平台应用的企鹅媒体用户、QqTpAppPenguin)、article_type(文章类型、ArticleType)、article_category(文章分类、ArticleCategory)、qq_article_category_normal(企鹅号的文章类型(文章)的文章分类、QqArticleCategoryNormal)、article(文章、Article)、qq_article_normal(企鹅号的文章类型(文章)的文章、QqArticleNormal)、qq_tp_app_access_token(企鹅号的第三方服务平台应用的访问令牌(Redis)、RedisQqAuthQqTpAppAccessToken),示例中仅演示前2个模型的填充、验证的实现3、发布文章类型:标准(普通、图文)的文章至渠道发布 /qq/v1/articles(article/create),请求参数并未严格遵循(表名_字段名)的规则,因为严格遵循的话,会导致字段名过长,且仍然可能存在不容易区分的问题,需要后续手动转换为对应模型的字段
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 | 1、请求参数列表 (1)uuid:必填,企鹅号ID(UUID) (2)article_type_code:必填,文章类型代码,standard:标准(普通) (3)article_category_id:必填,文章分类ID (4)title:必填,标题 (5)author:可选,作者,默认:空字符串 (6)source:必填,来源,xContent:内容库;vms:视频管理系统;cms:内容管理系统;spider:自媒体 (7)source_user_id:必填,来源用户ID (8)source_article_id:必填,来源文章ID (9)content:必填,文章内容 (10)cover_pic:必填,文章封面图 (11)cover_type:可选,文章封面类型,1:单图;3:三图,默认:1 (12)tag:可选,文章标签,以英文半角逗号分隔,默认:空字符串 (13)apply:可选,是否申请原创文章,0:否;1:是(需要用户具有发表图文原创文章资格否则无效),默认:0 (14)original_platform:可选,原创首发平台,申请原创文章时必填,默认:0 (15)original_url:可选,原创首发链接,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 (16)original_author:可选,原创首发作者,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 2、输入数据验证规则 (1)必填:uuid、article_type_code、article_category_id、title、source、source_user_id、source_article_id、content、cover_pic (2)默认值(''):author、tag、original_url、original_author (3)默认值(1):cover_type (4)默认值(0):apply、original_platform (5)比对:article_type_code 其值必须等于 standard (6)存在性:uuid 必须存在于企鹅号的第三方服务平台应用的企鹅媒体用户模型中,且其状态为 1:启用 |
4、新建模型文件:\common\logics\QqArticleStandardCreateParam.php,其作用为设置输入数据验证规则中的前4条与第6条、确保所有参数值为存在的,便于转换为对应模型字段时,无需再次判断其值是否存在
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 | <?php namespace common\logics; use Yii; use yii\base\Model; /** * QqArticleStandardCreateParam */ class QqArticleStandardCreateParam extends Model { public $uuid ; public $article_type_code ; public $article_category_id ; public $title ; public $author ; public $source ; public $source_user_id ; public $source_article_id ; public $content ; public $cover_pic ; public $cover_type ; public $tag ; public $apply ; public $original_platform ; public $original_url ; public $original_author ; /** * {@inheritdoc} */ public function rules() { return [ [[ 'uuid' , 'article_type_code' , 'article_category_id' , 'title' , 'source' , 'source_user_id' , 'source_article_id' , 'content' , 'cover_pic' ], 'required' ], [[ 'author' , 'tag' , 'original_url' , 'original_author' ], 'default' , 'value' => '' ], [[ 'cover_type' ], 'default' , 'value' => 1], [[ 'apply' , 'original_platform' ], 'default' , 'value' => 0], [ 'article_type_code' , 'compare' , 'compareValue' => ArticleType::CODE_STANDARD], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'uuid' => Yii::t( 'model/qq-article-standard-create-param' , 'Uuid' ), 'article_type_code' => Yii::t( 'model/qq-article-standard-create-param' , 'Article Type Code' ), 'article_category_id' => Yii::t( 'model/qq-article-standard-create-param' , 'Article Category Id' ), 'title' => Yii::t( 'model/qq-article-standard-create-param' , 'Title' ), 'author' => Yii::t( 'model/qq-article-standard-create-param' , 'Author' ), 'source' => Yii::t( 'model/qq-article-standard-create-param' , 'Source' ), 'source_user_id' => Yii::t( 'model/qq-article-standard-create-param' , 'Source User Id' ), 'source_article_id' => Yii::t( 'model/qq-article-standard-create-param' , 'Source Article Id' ), 'content' => Yii::t( 'model/qq-article-standard-create-param' , 'Content' ), 'cover_pic' => Yii::t( 'model/qq-article-standard-create-param' , 'Cover Pic' ), 'cover_type' => Yii::t( 'model/qq-article-standard-create-param' , 'Cover Type' ), 'tag' => Yii::t( 'model/qq-article-standard-create-param' , 'Tag' ), 'apply' => Yii::t( 'model/qq-article-standard-create-param' , 'Apply' ), 'original_platform' => Yii::t( 'model/qq-article-standard-create-param' , 'Original Platform' ), 'original_url' => Yii::t( 'model/qq-article-standard-create-param' , 'Original Url' ), 'original_author' => Yii::t( 'model/qq-article-standard-create-param' , 'Original Author' ), ]; } } |
5、对应的语言包文件
\common\messages\en-US\model\qq-article-standard-create-param.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php /** * Created by PhpStorm. * User: WangQiang * Date: 2018/08/31 * Time: 18:17 */ return [ 'Uuid' => 'Uuid' , 'Article Type Code' => 'Article Type Code' , 'Article Category Id' => 'Article Category Id' , 'Title' => 'Title' , 'Author' => 'Author' , 'Source' => 'Source' , 'Source User Id' => 'Source User Id' , 'Source Article Id' => 'Source Article Id' , 'Content' => 'Content' , 'Cover Pic' => 'Cover Pic' , 'Cover Type' => 'Cover Type' , 'Tag' => 'Tag' , 'Category' => 'Category' , 'Apply' => 'Apply' , 'Original Platform' => 'Original Platform' , 'Original Url' => 'Original Url' , 'Original Author' => 'Original Author' , ]; |
\common\messages\zh-CN\model\qq-article-standard-create-param.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php /** * Created by PhpStorm. * User: WangQiang * Date: 2018/08/31 * Time: 18:26 */ return [ 'Uuid' => '企鹅号ID(UUID)' , 'Article Type Code' => '文章类型代码' , 'Article Category Id' => '文章分类ID' , 'Title' => '标题' , 'Author' => '作者' , 'Source' => '来源' , 'Source User Id' => '来源用户ID' , 'Source Article Id' => '来源文章ID' , 'Content' => '文章内容' , 'Cover Pic' => '文章封面图' , 'Cover Type' => '文章封面类型,1:单图;3:三图' , 'Tag' => '文章标签,以英文半角逗号分隔' , 'Category' => '文章分类编号,即企鹅号的文章类型(文章)的文章分类ID' , 'Apply' => '是否申请原创文章,0:否;1:是(需要用户具有发表图文原创文章资格否则无效)' , 'Original Platform' => '原创首发平台,申请原创文章时必填' , 'Original Url' => '原创首发链接,申请原创文章时当选择平台不是企鹅号时必填' , 'Original Author' => '原创首发作者,申请原创文章时当选择平台不是企鹅号时必填' , ]; |
6、在应用的模型目录中,编辑 \qq\models\Article.php,定义场景
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 | <?php namespace qq\models; /** * This is the model class for table "{{%article}}". * * @see Article */ class Article extends \common\logics\Article { const SCENARIO_STANDARD_CREATE = 'qq_article_standard_create' ; /** * {@inheritdoc} */ public function scenarios() { $scenarios = parent::scenarios(); return $scenarios ; } /** * @inheritdoc */ public function rules() { $rules = [ ]; $parentRules = parent::rules(); return ArrayHelper::merge( $rules , $parentRules ); } /** * {@inheritdoc} * @return ArticleQuery the active query used by this AR class. */ public static function find() { return new ArticleQuery(get_called_class()); } } |
7、公共目录的模型数据层,qq_tp_app_penguin(企鹅号的第三方服务平台应用的企鹅媒体用户、QqTpAppPenguin)、\common\models\QqTpAppPenguin.php,代码如下
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 | <?php namespace common\models; use Yii; /** * This is the model class for table "{{%qq_tp_app_penguin}}". * * @property int $id * @property string $uuid 企鹅号ID(UUID) * @property int $qq_tp_app_id 企鹅号的第三方服务平台应用ID * @property string $openid 授权第三方用户的企鹅媒体用户唯一标识 * @property int $status 状态,-1:删除;0:禁用;1:启用 * @property int $created_at 创建时间 * @property int $updated_at 更新时间 */ class QqTpAppPenguin extends \yii\db\ActiveRecord { /** * {@inheritdoc} */ public static function tableName() { return '{{%qq_tp_app_penguin}}' ; } /** * {@inheritdoc} */ public function rules() { return [ [[ 'uuid' , 'qq_tp_app_id' , 'openid' ], 'required' ], [[ 'qq_tp_app_id' , 'status' , 'created_at' , 'updated_at' ], 'integer' ], [[ 'uuid' ], 'string' , 'max' => 64], [[ 'openid' ], 'string' , 'max' => 32], [[ 'uuid' ], 'unique' ], [[ 'openid' ], 'unique' ], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => Yii::t( 'model/qq-tp-app-penguin' , 'ID' ), 'uuid' => Yii::t( 'model/qq-tp-app-penguin' , 'Uuid' ), 'qq_tp_app_id' => Yii::t( 'model/qq-tp-app-penguin' , 'Qq Tp App ID' ), 'openid' => Yii::t( 'model/qq-tp-app-penguin' , 'Openid' ), 'status' => Yii::t( 'model/qq-tp-app-penguin' , 'Status' ), 'created_at' => Yii::t( 'model/qq-tp-app-penguin' , 'Created At' ), 'updated_at' => Yii::t( 'model/qq-tp-app-penguin' , 'Updated At' ), ]; } /** * {@inheritdoc} * @return QqTpAppPenguinQuery the active query used by this AR class. */ public static function find() { return new QqTpAppPenguinQuery(get_called_class()); } } |
8、公共目录的模型逻辑层,qq_tp_app_penguin(企鹅号的第三方服务平台应用的企鹅媒体用户、QqTpAppPenguin)、\common\logics\QqTpAppPenguin.php,代码如下
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 | <?php namespace common\logics; use Yii; use yii\behaviors\TimestampBehavior; use yii2tech\ar\softdelete\SoftDeleteBehavior; use common\behaviors\UUIDBehavior; use yii\helpers\ArrayHelper; class QqTpAppPenguin extends \common\models\QqTpAppPenguin { const STATUS_DELETED = -1; //状态:删除 const STATUS_DISABLED = 0; //状态:禁用 const STATUS_ENABLED = 1; //状态:启用 /** * @inheritdoc */ public function behaviors() { return [ 'timestampBehavior' => [ 'class' => TimestampBehavior::className(), 'attributes' => [ self::EVENT_BEFORE_INSERT => [ 'created_at' , 'updated_at' ], self::EVENT_BEFORE_UPDATE => 'updated_at' , SoftDeleteBehavior::EVENT_BEFORE_SOFT_DELETE => 'updated_at' , ] ], 'uuid' => [ 'class' => UUIDBehavior::className(), 'column' => 'uuid' , ], 'softDeleteBehavior' => [ 'class' => SoftDeleteBehavior::className(), 'softDeleteAttributeValues' => [ 'status' => self::STATUS_DELETED ], ], ]; } /** * {@inheritdoc} */ public function scenarios() { $scenarios = parent::scenarios(); return $scenarios ; } /** * @inheritdoc */ public function rules() { $rules = [ ]; $parentRules = parent::rules(); return ArrayHelper::merge( $rules , $parentRules ); } /** * {@inheritdoc} * @return QqTpAppPenguinQuery the active query used by this AR class. */ public static function find() { return new QqTpAppPenguinQuery(get_called_class()); } } |
9、在应用的模型目录中,qq_tp_app_penguin(企鹅号的第三方服务平台应用的企鹅媒体用户、QqTpAppPenguin)、\qq\models\QqTpAppPenguin.php,定义具体场景的验证规则,代码如下
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 | <?php /** * Created by PhpStorm. * User: WangQiang * Date: 2018/08/28 * Time: 15:10 */ namespace qq\models; use Yii; use yii\helpers\ArrayHelper; use yii\web\ServerErrorHttpException; /** * This is the model class for table "{{%qq_tp_app_penguin}}". * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class QqTpAppPenguin extends \common\logics\QqTpAppPenguin { /** * {@inheritdoc} */ public function scenarios() { $scenarios = parent::scenarios(); $scenarios [Article::SCENARIO_STANDARD_CREATE] = [ 'uuid' ]; return $scenarios ; } /** * @inheritdoc */ public function rules() { $rules = [ /* 发布文章类型:标准(普通、图文)的文章 */ [[ 'uuid' ], 'required' , 'on' => Article::SCENARIO_STANDARD_CREATE], [ 'uuid' , 'exist' , 'filter' => [ 'status' => self::STATUS_ENABLED], 'on' => Article::SCENARIO_STANDARD_CREATE], [[ 'qq_tp_app_id' , 'openid' ], 'required' ], ]; $parentRules = parent::rules(); unset( $parentRules [0], $parentRules [4]); return ArrayHelper::merge( $rules , $parentRules ); } /** * {@inheritdoc} * @return QqTpAppPenguinQuery the active query used by this AR class. */ public static function find() { return new QqTpAppPenguinQuery(get_called_class()); } } |
10、编辑方法文件 \qq\rests\article\CreateAction.php
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace qq\rests\article; use Yii; use yii\base\Model; use qq\models\QqArticleStandardCreateParam; use qq\models\ArticleType; use qq\models\Article; use qq\models\QqTpAppPenguin; use qq\services\QqArticleService; use yii\helpers\Url; use yii\helpers\ArrayHelper; use yii\web\ServerErrorHttpException; /** * 发布文章类型:标准(普通、图文)的文章至渠道发布 * * 1、请求参数列表 * (1)uuid:必填,企鹅号ID(UUID) * (2)article_type_code:必填,文章类型代码,standard:标准(普通) * (3)article_category_id:必填,文章分类ID * (4)title:必填,标题 * (5)author:可选,作者,默认:空字符串 * (6)source:必填,来源,xContent:内容库;vms:视频管理系统;cms:内容管理系统;spider:自媒体 * (7)source_user_id:必填,来源用户ID * (8)source_article_id:必填,来源文章ID * (9)content:必填,文章内容 * (10)cover_pic:必填,文章封面图 * (11)cover_type:可选,文章封面类型,1:单图;3:三图,默认:1 * (12)tag:可选,文章标签,以英文半角逗号分隔,默认:空字符串 * (13)apply:可选,是否申请原创文章,0:否;1:是(需要用户具有发表图文原创文章资格否则无效),默认:0 * (14)original_platform:可选,原创首发平台,申请原创文章时必填,默认:0 * (15)original_url:可选,原创首发链接,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 * (16)original_author:可选,原创首发作者,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 * * 2、输入数据验证规则 * (1)必填:uuid、article_type_code、article_category_id、title、source、source_user_id、source_article_id、content、cover_pic * (2)默认值(''):author、tag、original_url、original_author * (3)默认值(1):cover_type * (4)默认值(0):apply、original_platform * (5)比对:article_type_code 其值必须等于 standard * (6)存在性:uuid 必须存在于企鹅号的第三方服务平台应用的企鹅媒体用户模型中,且其状态为 1:启用 * * For more details and usage information on CreateAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class CreateAction extends Action { /** * @var string the scenario to be assigned to the new model before it is validated and saved. */ public $scenario = Model::SCENARIO_DEFAULT; /** * @var string the name of the view action. This property is need to create the URL when the model is successfully created. */ public $viewAction = 'view' ; /** * 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' ]]; } return [ 'code' => 10000, 'message' => Yii::t( 'app' , '10003' ), 'data' => '' ]; } /** * 处理模型填充与验证 * @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.' ); } } } |
11、Post http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,响应:数据验证失败:企鹅号ID(UUID)不能为空。,符合预期
1 2 | { } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)不能为空。" } |
12、Post http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,缺少参数:original_author 时,打印:$qqArticleStandardCreateParam,original_author 的值为空字符串,符合预期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | { "uuid": "e88e79faad9011e8a14554ee75d2ebc1", "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180901 - 1", "author": "作者 - 20180901 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180901 - 1", "cover_pic": "http://b.hiphotos.baidu.com/image/pic/item/1e30e924b899a901a5be490c10950a7b0208f505.jpg", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | qq\models\QqArticleStandardCreateParam Object ( [uuid] => e88e79faad9011e8a14554ee75d2ebc1 [article_type_code] => standard [article_category_id] => 1 [title] => 标题 - 20180901 - 1 [author] => 作者 - 20180901 - 1 [source] => spider [source_user_id] => 1 [source_article_id] => 1 [content] => 文章内容 - 20180901 - 1 [cover_pic] => http://b.hiphotos.baidu.com/image/pic/item/1e30e924b899a901a5be490c10950a7b0208f505.jpg [cover_type] => 1 [tag] => [apply] => 0 [original_platform] => 0 [original_url] => [original_author] => [_errors:yii\base\Model:private] => Array ( ) ) |
13、Post http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,参数:uuid 不存在于企鹅号的第三方服务平台应用的企鹅媒体用户模型中,响应:数据验证失败:企鹅号ID(UUID)是无效的。,符合预期,如图2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "uuid": "e88e79faad9011e8a14554ee75d2ebc10", "article_type_code": "standard", "article_category_id": 1, "title": "标题 - 20180901 - 1", "author": "作者 - 20180901 - 1", "source": "spider", "source_user_id": 1, "source_article_id": 1, "content": "文章内容 - 20180901 - 1", "cover_pic": "http://b.hiphotos.baidu.com/image/pic/item/1e30e924b899a901a5be490c10950a7b0208f505.jpg", "cover_type": 1, "tag": "", "apply": 0, "original_platform": 0, "original_url": "", "original_author": "" } |
1 2 3 4 | { "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" } |
14、查看日志,其验证过程中的 SQL 语句
1 | SELECT EXISTS( SELECT * FROM `cpa_qq_tp_app_penguin` WHERE (`cpa_qq_tp_app_penguin`.`uuid`= 'e88e79faad9011e8a14554ee75d2ebc10' ) AND (`status`=1)) |
15、后续其他模型的验证可以沿用 uuid 的验证方案,便可以实现请求参数为多模型时,数据的填充、验证,\qq\rests\article\CreateAction.php 最终的代码
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace qq\rests\article; use Yii; use yii\base\Model; use qq\models\QqArticleStandardCreateParam; use qq\models\ArticleCategory; use qq\models\QqArticleCategoryNormal; use qq\models\Article; use qq\models\QqTpAppPenguin; use qq\models\QqArticleNormal; use qq\models\redis\qq_auth\QqTpAppAccessToken as RedisQqAuthQqTpAppAccessToken; use qq\services\QqArticleService; use yii\helpers\Url; use yii\helpers\ArrayHelper; use yii\web\ServerErrorHttpException; use yii\web\HttpException; /** * 发布文章类型:标准(普通、图文)的文章至渠道发布 * * 1、请求参数列表 * (1)uuid:必填,企鹅号ID(UUID) * (2)article_type_code:必填,文章类型代码,standard:标准(普通) * (3)article_category_id:必填,文章分类ID * (4)title:必填,标题 * (5)author:可选,作者,默认:空字符串 * (6)source:必填,来源,xContent:内容库;vms:视频管理系统;cms:内容管理系统;spider:自媒体 * (7)source_user_id:必填,来源用户ID * (8)source_article_id:必填,来源文章ID * (9)content:必填,文章内容 * (10)cover_pic:必填,文章封面图 * (11)cover_type:可选,文章封面类型,1:单图;3:三图,默认:1 * (12)tag:可选,文章标签,以英文半角逗号分隔,默认:空字符串 * (13)apply:可选,是否申请原创文章,0:否;1:是(需要用户具有发表图文原创文章资格否则无效),默认:0 * (14)original_platform:可选,原创首发平台,申请原创文章时必填,默认:0 * (15)original_url:可选,原创首发链接,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 * (16)original_author:可选,原创首发作者,申请原创文章时当选择平台不是企鹅号时必填,默认:空字符串 * * 2、输入数据验证规则 * (1)必填:uuid、article_type_code、article_category_id、title、source、source_user_id、source_article_id、content、cover_pic * (2)默认值(''):author、tag、original_url、original_author * (3)默认值(1):cover_type * (4)默认值(0):apply、original_platform * (5)比对:article_type_code 其值必须等于 standard * (6)存在性:uuid 必须存在于企鹅号的第三方服务平台应用的企鹅媒体用户模型中,且其状态为 1:启用 * (7)存在性:article_category_id 必须存在于文章分类模型中,且其状态为 1:启用 * (8)存在性:article_category_id 必须存在于企鹅号的文章类型(文章)的文章分类模型中,且其状态为 1:启用 * (9)字符串(最大长度:32):group_id、source * (10)字符串(最大长度:64):author * (11)字符串(最大长度:255):title * (12)整数:source_user_id、source_article_id * (13)范围(['xContent', 'vms', 'cms', 'spider']):source * (14)字符串:content * (15)字符串(最大长度:64):original_author * (16)字符串(最大长度:255):cover_pic、tag、original_url * (17)整数:cover_type、apply、original_platform * (18)范围([1, 3]):cover_type * (19)范围([0, 1]):apply * (20)范围([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]):original_platform * (21)网址:original_url * (22)必填:original_platform(当 apply 等于 1 时) * (23)范围([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]):original_platform(当 apply 等于 1 时) * (24)必填:original_url(当 apply 等于 1 且 original_platform 不等于 1 时) * (25)必填:original_author(当 apply 等于 1 且 original_platform 不等于 1 时) * (26)存在性:uuid 必须存在于企鹅号的第三方服务平台应用的访问令牌(Redis)模型中,且其状态为 1:启用 * (27)用户刷新令牌有效截止时间必须 大于等于 服务器时间 * * 3、操作数据(事务) * (1)插入数据 * * For more details and usage information on CreateAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class CreateAction extends Action { /** * @var string the scenario to be assigned to the new model before it is validated and saved. */ public $scenario = Model::SCENARIO_DEFAULT; /** * @var string the name of the view action. This property is need to create the URL when the model is successfully created. */ public $viewAction = 'view' ; /** * 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' ]]; } // 文章分类 $articleCategory = new ArticleCategory([ 'scenario' => $this ->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams [ $articleCategory ->formName()][ 'id' ] = $qqArticleStandardCreateParam ->article_category_id; $articleCategoryResult = self::handleLoadAndValidate( $articleCategory , $requestParams ); if ( $articleCategoryResult [ 'status' ] === false) { return [ 'code' => $articleCategoryResult [ 'code' ], 'message' => $articleCategoryResult [ 'message' ]]; } // 如果当前场景为:qq_article_standard_create if ( $this ->scenario == Article::SCENARIO_STANDARD_CREATE) { // 文章分类 $qqArticleCategoryNormal = new QqArticleCategoryNormal([ 'scenario' => $this ->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams [ $qqArticleCategoryNormal ->formName()][ 'article_category_id' ] = $qqArticleStandardCreateParam ->article_category_id; $qqArticleCategoryNormalResult = self::handleLoadAndValidate( $qqArticleCategoryNormal , $requestParams ); if ( $qqArticleCategoryNormalResult [ 'status' ] === false) { return [ 'code' => $qqArticleCategoryNormalResult [ 'code' ], 'message' => $qqArticleCategoryNormalResult [ 'message' ]]; } } // 文章 $model = new $this ->modelClass([ 'scenario' => $this ->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams [ $model ->formName()] = [ 'group_id' => $requestParams [ 'group_id' ], 'title' => $qqArticleStandardCreateParam ->title, 'author' => $qqArticleStandardCreateParam ->author, 'source' => $qqArticleStandardCreateParam ->source, 'source_user_id' => $qqArticleStandardCreateParam ->source_user_id, 'source_article_id' => $qqArticleStandardCreateParam ->source_article_id, ]; $modelResult = self::handleLoadAndValidate( $model , $requestParams ); if ( $modelResult [ 'status' ] === false) { return [ 'code' => $modelResult [ 'code' ], 'message' => $modelResult [ 'message' ]]; } // 如果当前场景为:qq_article_standard_create if ( $this ->scenario == Article::SCENARIO_STANDARD_CREATE) { // 企鹅号的文章类型(文章)的文章 $qqArticleNormal = new QqArticleNormal([ 'scenario' => $this ->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams [ $qqArticleNormal ->formName()] = [ 'content' => $qqArticleStandardCreateParam ->content, 'cover_pic' => $qqArticleStandardCreateParam ->cover_pic, 'cover_type' => $qqArticleStandardCreateParam ->cover_type, 'tag' => $qqArticleStandardCreateParam ->tag, 'apply' => $qqArticleStandardCreateParam ->apply, 'original_platform' => $qqArticleStandardCreateParam ->original_platform, 'original_url' => $qqArticleStandardCreateParam ->original_url, 'original_author' => $qqArticleStandardCreateParam ->original_author, ]; $qqArticleNormalResult = self::handleLoadAndValidate( $qqArticleNormal , $requestParams ); if ( $qqArticleNormalResult [ 'status' ] === false) { return [ 'code' => $qqArticleNormalResult [ 'code' ], 'message' => $qqArticleNormalResult [ 'message' ]]; } } // 企鹅号的第三方服务平台应用的访问令牌(Redis) $redisQqAuthQqTpAppAccessToken = new RedisQqAuthQqTpAppAccessToken([ 'scenario' => $this ->scenario, ]); // 转换标准(普通、图文)的文章发布参数,多模型的填充、验证的实现 $requestParams [ $redisQqAuthQqTpAppAccessToken ->formName()][ 'qq_tp_app_penguin_uuid' ] = $qqArticleStandardCreateParam ->uuid; $redisQqAuthQqTpAppAccessTokenResult = self::handleLoadAndValidate( $redisQqAuthQqTpAppAccessToken , $requestParams ); if ( $redisQqAuthQqTpAppAccessTokenResult [ 'status' ] === false) { throw new HttpException(302, Yii::t( 'error' , '40008' ), 40008); } return [ 'code' => 10000, 'message' => Yii::t( 'app' , '10003' ), 'data' => '' ]; } /** * 处理模型填充与验证 * @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.' ); } } } |
近期评论