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
=> 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.');
}
}
}
原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/181209.html
![参考网址:https://www.yiiframework.com/doc/guide/2.0/zh-cn/input-multiple-models ,其用于网页表单是合适的,不过 API 应用的请求参数一般并未添加表单名称(尤其是单个模型输入时),因此,不太合适,例:表名为 article_type,字段名为 code,那么请求参数名为 article_type_code,而不是:ArticleType['code'],网页表单](https://blog.ytso.com/wp-content/themes/justnews/themer/assets/images/lazy.png)