基于 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、请求参数列表 (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条、确保所有参数值为存在的,便于转换为对应模型字段时,无需再次判断其值是否存在
<?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
<?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
<?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,定义场景
<?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,代码如下
<?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,代码如下
<?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,定义具体场景的验证规则,代码如下
<?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
<?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)不能为空。,符合预期
{ }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)不能为空。" }
12、Post http://api.channel-pub-api.localhost/qq/v1/articles?group_id=015ce30b116ce86058fa6ab4fea4ac63 ,缺少参数:original_author 时,打印:$qqArticleStandardCreateParam,original_author 的值为空字符串,符合预期
{ "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": "" }
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
{ "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": "" }
{ "code": 20004, "message": "数据验证失败:企鹅号ID(UUID)是无效的。" }
14、查看日志,其验证过程中的 SQL 语句
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 最终的代码
<?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.'); } } }
近期评论