1、查看 rest/ActiveController.php,发现默认的动作方法列表
/**
* {@inheritdoc}
*/
public function actions()
{
return [
'index' => [
'class' => 'yii/rest/IndexAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'view' => [
'class' => 'yii/rest/ViewAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'create' => [
'class' => 'yii/rest/CreateAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->createScenario,
],
'update' => [
'class' => 'yii/rest/UpdateAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->updateScenario,
],
'delete' => [
'class' => 'yii/rest/DeleteAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'options' => [
'class' => 'yii/rest/OptionsAction',
],
];
}
2、yii/rest/ActiveController 默认提供以下动作:
index:按页列出资源 view:返回指定资源的详情 create:创建新的资源 update:更新一个存在的资源 delete:删除指定的资源 options:返回支持的 HTTP 方法
3、现有一个新的需求,在原型中已经体现,当 租户设置 – 选题紧急程度为关闭时,在新建选题页面中,字段:选题紧急程度不显示;,当 租户设置 – 选题紧急程度为开启时,在新建选题页面中,字段:选题紧急程度显示,如图1
4、在现阶段的实现中,RESTful API 仅提供了 3 个接口,分别为:
create:创建新的资源 edit:编辑一个存在的资源(获取表单数据) update:更新一个存在的资源
5、因此,决定再添加一个新的接口,new:新建新的资源(获取表单数据),动作方法命名为:new,参考来源为 WordPress,之前的动作方法:edit,同样参考自 WordPress,如图2
new:新建新的资源(获取表单数据)
6、新建动作方法文件:api/rests/plan/NewAction.php
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace api/rests/plan;
use Yii;
use api/models/ConfigTask;
use api/models/Plan;
use api/models/redis/cmc_console/User as RedisCmcConsoleUser;
use api/services/ConfigGroupService;
/**
* 新建选题(获取表单数据):/plans/new(plan/new)
*
* For more details and usage information on NewAction, see the [guide article on rest controllers](guide:rest-controllers).
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class NewAction extends Action
{
/**
* News a new model.
* @return array the model being displayed
*/
public function run()
{
if ($this->checkAccess) {
call_user_func($this->checkAccess, $this->id);
}
// 当前用户的身份实例,未认证用户则为 Null
/* @var $identity RedisCmcConsoleUser */
$identity = Yii::$app->user->identity;
/* @var $modelClass Plan */
$modelClass = $this->modelClass;
$model = new $modelClass;
$data = $model->attributes;
unset($data['id'], $data['group_id'], $data['create_user_id'], $data['create_name'], $data['emergency_is_open'], $data['material_asset_id'], $data['prev_status'], $data['is_not_isolated'], $data['is_deleted'], $data['created_at'], $data['updated_at'], $data['deleted_at']);
// 基于租户ID获取状态为启用的租户配置数据
$configGroupData = ConfigGroupService::getDataEnabledByGroupId($identity->group_id);
// 给请求参数赋默认值
$stringAttribute = ['title', 'place', 'opinion', 'content'];
$intAttribute = ['config_column_id', 'occur_at', 'ended_at', 'importance', 'emergency', 'is_auto_task_create', 'is_united', 'status'];
$arrayAttribute = ['keyword'];
$time = time();
foreach ($data as $key => $value) {
if (in_array($key, $stringAttribute)) {
if ($key == 'place') {
$data[$key] = $configGroupData['base_location_name'] . $configGroupData['base_location_address'];
} else {
$data[$key] = '';
}
}
if (in_array($key, $intAttribute)) {
if ($key == 'importance') {
$data[$key] = $model::IMPORTANCE_DEFAULT;
} elseif ($key == 'emergency') {
$data[$key] = $model::EMERGENCY_DEFAULT;
} elseif ($key == 'occur_at') {
$data[$key] = $time;
} elseif ($key == 'ended_at') {
$data[$key] = strtotime('+7 day', time());
} elseif ($key == 'status') {
$data[$key] = $model::STATUS_EDITED;
} else {
$data[$key] = 0;
}
}
if (in_array($key, $arrayAttribute)) {
$data[$key] = [];
}
}
// 素材的资源列表
$materialAssetsField = 'material_assets';
$data[$materialAssetsField] = [];
// 选题的参与用户列表
$planAttendedExecUsersField = 'plan_attended_exec_user_ids';
$planAttendedAttendedUsersField = 'plan_attended_attended_user_ids';
$data[$planAttendedExecUsersField] = [];
$data[$planAttendedAttendedUsersField] = [];
// 字段列表(是否允许编辑,0:否;1:是)
$fields = [];
$canEditableFields = ['title', 'config_column_id', 'occur_at', 'place', 'content', 'ended_at', 'importance', 'is_auto_task_create', 'keyword', 'opinion', 'is_united', $materialAssetsField, $planAttendedExecUsersField, $planAttendedAttendedUsersField, 'status', 'emergency'];
// 字段列表(是否显示,0:否;1:是)
$displayableFields = [];
$canDisplayableFields = $canEditableFields;
// 基于租户ID查找资源(模型:任务配置)(状态:启用;是否默认:是)列表
$configTaskEnabledIsDefaultYesItems = ConfigTask::findAllEnabledIsDefaultYesByGroupId($identity->group_id);
foreach ($data as $fieldKey => $fieldValue) {
$fields[$fieldKey] = 0;
$displayableFields[$fieldKey] = 0;
if (in_array($fieldKey, $canEditableFields)) {
$fields[$fieldKey] = 1;
// 是否自动创建任务 && 不存在默认的任务配置(是否允许编辑,0:否)
if ($fieldKey == 'is_auto_task_create' && empty($configTaskEnabledIsDefaultYesItems)) {
$fields[$fieldKey] = 0;
}
// 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否)
if ($fieldKey == 'emergency' && $configGroupData['plan_emergency_is_open'] == $model::EMERGENCY_IS_OPEN_NO) {
$fields[$fieldKey] = 0;
}
}
if (in_array($fieldKey, $canDisplayableFields)) {
$displayableFields[$fieldKey] = 1;
// 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否)
if ($fieldKey == 'emergency' && $configGroupData['plan_emergency_is_open'] == $model::EMERGENCY_IS_OPEN_NO) {
$displayableFields[$fieldKey] = 0;
}
}
}
$data['fields'] = $fields;
$data['displayable_fields'] = $displayableFields;
return ['code' => 10000, 'message' => Yii::t('success', '126046'), 'data' => $data];
}
}
7、在 Postman 中 GET:http://api.pcs-api.localhost/v1/plans/new ,响应参数,如图3
{
"code": 10000,
"message": "新建选题(获取表单数据)成功",
"data": {
"title": "",
"config_column_id": 0,
"occur_at": 1576648175,
"place": "南山区的基地名称详细地址",
"content": "",
"ended_at": 1577252975,
"importance": 3,
"emergency": 3,
"is_auto_task_create": 0,
"keyword": [],
"opinion": "",
"is_united": 0,
"status": 1,
"material_assets": [],
"plan_attended_exec_user_ids": [],
"plan_attended_attended_user_ids": [],
"fields": {
"title": 1,
"config_column_id": 1,
"occur_at": 1,
"place": 1,
"content": 1,
"ended_at": 1,
"importance": 1,
"emergency": 1,
"is_auto_task_create": 1,
"keyword": 1,
"opinion": 1,
"is_united": 1,
"status": 1,
"material_assets": 1,
"plan_attended_exec_user_ids": 1,
"plan_attended_attended_user_ids": 1
},
"displayable_fields": {
"title": 1,
"config_column_id": 1,
"occur_at": 1,
"place": 1,
"content": 1,
"ended_at": 1,
"importance": 1,
"emergency": 1,
"is_auto_task_create": 1,
"keyword": 1,
"opinion": 1,
"is_united": 1,
"status": 1,
"material_assets": 1,
"plan_attended_exec_user_ids": 1,
"plan_attended_attended_user_ids": 1
}
}
}
8、在响应参数中包含一些字段的默认值,前端与移动端在接收到响应数据后,可以基于其渲染表单数据,以保证前端与移动端的默认值的一致性,且默认值由接口控制,在需要调整默认值时,更为灵活。某个字段不存在默认值时,并未赋值为:null,原因在于如果赋值为:null,字段类型无法做到固定不变化。最终基于字段类型分别赋值为:空字符串、0、空数组。不过当某字段的类型为数字时,且其值为 0,客户端无法得知某字段是否具有默认值。
9、决定再添加一个字段:default_fields,用以标识某个字段的值是否为默认值。编辑动作方法文件:api/rests/plan/NewAction.php
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace api/rests/plan;
use Yii;
use api/models/ConfigTask;
use api/models/Plan;
use api/models/redis/cmc_console/User as RedisCmcConsoleUser;
use api/services/ConfigGroupService;
/**
* 新建选题(获取表单数据):/plans/new(plan/new)
*
* For more details and usage information on NewAction, see the [guide article on rest controllers](guide:rest-controllers).
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class NewAction extends Action
{
/**
* News a new model.
* @return array the model being displayed
*/
public function run()
{
if ($this->checkAccess) {
call_user_func($this->checkAccess, $this->id);
}
// 当前用户的身份实例,未认证用户则为 Null
/* @var $identity RedisCmcConsoleUser */
$identity = Yii::$app->user->identity;
/* @var $modelClass Plan */
$modelClass = $this->modelClass;
$model = new $modelClass;
$data = $model->attributes;
unset($data['id'], $data['group_id'], $data['create_user_id'], $data['create_name'], $data['emergency_is_open'], $data['material_asset_id'], $data['prev_status'], $data['is_not_isolated'], $data['is_deleted'], $data['created_at'], $data['updated_at'], $data['deleted_at']);
// 基于租户ID获取状态为启用的租户配置数据
$configGroupData = ConfigGroupService::getDataEnabledByGroupId($identity->group_id);
// 给请求参数赋默认值
$stringAttribute = ['title', 'place', 'opinion', 'content'];
$intAttribute = ['config_column_id', 'occur_at', 'ended_at', 'importance', 'emergency', 'is_auto_task_create', 'is_united', 'status'];
$arrayAttribute = ['keyword'];
$time = time();
foreach ($data as $key => $value) {
if (in_array($key, $stringAttribute)) {
if ($key == 'place') {
$data[$key] = $configGroupData['base_location_name'] . $configGroupData['base_location_address'];
} else {
$data[$key] = '';
}
}
if (in_array($key, $intAttribute)) {
if ($key == 'importance') {
$data[$key] = $model::IMPORTANCE_DEFAULT;
} elseif ($key == 'emergency') {
$data[$key] = $model::EMERGENCY_DEFAULT;
} elseif ($key == 'occur_at') {
$data[$key] = $time;
} elseif ($key == 'ended_at') {
$data[$key] = strtotime('+7 day', time());
} elseif ($key == 'status') {
$data[$key] = $model::STATUS_EDITED;
} else {
$data[$key] = 0;
}
}
if (in_array($key, $arrayAttribute)) {
$data[$key] = [];
}
}
// 素材的资源列表
$materialAssetsField = 'material_assets';
$data[$materialAssetsField] = [];
// 选题的参与用户列表
$planAttendedExecUsersField = 'plan_attended_exec_user_ids';
$planAttendedAttendedUsersField = 'plan_attended_attended_user_ids';
$data[$planAttendedExecUsersField] = [];
$data[$planAttendedAttendedUsersField] = [];
// 字段列表(是否允许编辑,0:否;1:是)
$fields = [];
$canEditableFields = ['title', 'config_column_id', 'occur_at', 'place', 'content', 'ended_at', 'importance', 'is_auto_task_create', 'keyword', 'opinion', 'is_united', $materialAssetsField, $planAttendedExecUsersField, $planAttendedAttendedUsersField, 'status', 'emergency'];
// 字段列表(是否默认,0:否;1:是)
$defaultFields = [];
$canDefaultFields = ['occur_at', 'place', 'ended_at', 'importance', 'emergency', 'is_auto_task_create', 'is_united', 'status'];
// 字段列表(是否显示,0:否;1:是)
$displayableFields = [];
$canDisplayableFields = $canEditableFields;
// 基于租户ID查找资源(模型:任务配置)(状态:启用;是否默认:是)列表
$configTaskEnabledIsDefaultYesItems = ConfigTask::findAllEnabledIsDefaultYesByGroupId($identity->group_id);
foreach ($data as $fieldKey => $fieldValue) {
$fields[$fieldKey] = 0;
$displayableFields[$fieldKey] = 0;
$defaultFields[$fieldKey] = 0;
if (in_array($fieldKey, $canEditableFields)) {
$fields[$fieldKey] = 1;
// 是否自动创建任务 && 不存在默认的任务配置(是否允许编辑,0:否)
if ($fieldKey == 'is_auto_task_create' && empty($configTaskEnabledIsDefaultYesItems)) {
$fields[$fieldKey] = 0;
}
}
if (in_array($fieldKey, $canDefaultFields)) {
$defaultFields[$fieldKey] = 1;
}
if (in_array($fieldKey, $canDisplayableFields)) {
$displayableFields[$fieldKey] = 1;
// 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否)
if ($fieldKey == 'emergency' && $configGroupData['plan_emergency_is_open'] == $model::EMERGENCY_IS_OPEN_NO) {
$displayableFields[$fieldKey] = 0;
}
}
}
$data['fields'] = $fields;
$data['displayable_fields'] = $displayableFields;
$data['default_fields'] = $defaultFields;
return ['code' => 10000, 'message' => Yii::t('success', '126046'), 'data' => $data];
}
}
10、在 Postman 中 GET:http://api.pcs-api.localhost/v1/plans/new ,响应参数,如图4
{
"code": 10000,
"message": "新建选题(获取表单数据)成功",
"data": {
"title": "",
"config_column_id": 0,
"occur_at": 1576720714,
"place": "南山区的基地名称详细地址",
"content": "",
"ended_at": 1577325514,
"importance": 3,
"emergency": 3,
"is_auto_task_create": 0,
"keyword": [],
"opinion": "",
"is_united": 0,
"status": 1,
"material_assets": [],
"plan_attended_exec_user_ids": [],
"plan_attended_attended_user_ids": [],
"fields": {
"title": 1,
"config_column_id": 1,
"occur_at": 1,
"place": 1,
"content": 1,
"ended_at": 1,
"importance": 1,
"emergency": 1,
"is_auto_task_create": 1,
"keyword": 1,
"opinion": 1,
"is_united": 1,
"status": 1,
"material_assets": 1,
"plan_attended_exec_user_ids": 1,
"plan_attended_attended_user_ids": 1
},
"displayable_fields": {
"title": 1,
"config_column_id": 1,
"occur_at": 1,
"place": 1,
"content": 1,
"ended_at": 1,
"importance": 1,
"emergency": 1,
"is_auto_task_create": 1,
"keyword": 1,
"opinion": 1,
"is_united": 1,
"status": 1,
"material_assets": 1,
"plan_attended_exec_user_ids": 1,
"plan_attended_attended_user_ids": 1
},
"default_fields": {
"title": 0,
"config_column_id": 0,
"occur_at": 1,
"place": 1,
"content": 0,
"ended_at": 1,
"importance": 1,
"emergency": 1,
"is_auto_task_create": 1,
"keyword": 0,
"opinion": 0,
"is_united": 1,
"status": 1,
"material_assets": 0,
"plan_attended_exec_user_ids": 0,
"plan_attended_attended_user_ids": 0
}
}
}
11、字段是否显示,在设计时,存在 2 种方案,第 1 种方案为:响应参数中,emergency 可以存在|不存在;第 2 种方案为:响应参数中,emergency 一直存在,然后在 displayable_fields[’emergency’] 中设置其值为 1|0。最终决定使用第 2 种方案。原因在于,以保证响应参数的字段数量与类型上皆无变化,避免客户端对于字段是否存在的判断处理,降低客户端判断处理的复杂度。
12、上传选题素材时,前端的资源的可接受上传的文件扩展名列表,是由前端自行配置的,与接口基于约定实现,但是,其弊端在于,一旦后端有所调整,前端也需要相应调整,否则就不一致,现在决定在响应参数中添加:config,在此参数中包含新建选题表单所需要的一些限制性规则。查看参数配置文件:common/config/params-local.php
// 策划指挥系统接口
'pcsApi' => [
'asset' => [ // 资源
'basePath' => 'E:/wwwroot/pcs-api/storage', // BASE PATH
'tempDir' => '/tmp', // TEMP DIR
'hostInfo' => 'http://127.0.0.1/pcs-api/storage', // HOME URL
'baseUrl' => '', // BASE URL
'upload' => [ // 上传
'extensions' => 'ogg, pdf, xml, zip, gz, mp4, mp3, wav, webm, gif, jpeg, jpg, png, webp, svg, svgz, tiff, css, csv, txt, vcf, vcard, mov, qt, mkv, mk3d, mka, mks, wmv, flv', // 可接受上传的文件扩展名列表
'mimeTypes' => 'application/ogg, application/pdf, application/xml, application/zip, application/gzip, audio/mp4, audio/mpeg, audio/ogg, audio/vnd.wave, audio/webm, image/gif, image/jpeg, image/png, image/webp, image/svg+xml, image/tiff, text/css, text/csv, text/plain, text/vcard, text/xml, video/mpeg, video/mp4, video/ogg, video/quicktime, video/webm, video/x-matroska, video/x-ms-wmv, video/x-flv', // 可接受上传的 MIME 类型列表
'minSize' => null, // 上传文件所需最少多少 Byte 的大小
'maxSize' => 1024 * 1024 * 1024, // 上传文件所需最多多少 Byte 的大小
'maxFiles' => 10, // 给定属性最多能承载多少个文件
'scenario' => [ // 场景
'configGroupBaseLocationIcon' => [ // 租户设置的基地的图标
'extensions' => 'jpeg, jpg, png', // 可接受上传的文件扩展名列表
'mimeTypes' => 'image/jpeg, image/png', // 可接受上传的 MIME 类型列表
'minSize' => null, // 上传文件所需最少多少 Byte 的大小
'maxSize' => 1024 * 1024 * 2, // 上传文件所需最多多少 Byte 的大小
'maxFiles' => 2, // 给定属性最多能承载多少个文件
'minWidth' => 50, // 图片的最小宽度
'maxWidth' => 200, // 图片的最大宽度
'minHeight' => 50, // 图片的最小高度
'maxHeight' => 200, // 图片的最大高度
],
'configUserGisAvatarCustomize' => [ // 用户设置的GIS大屏的自定义的头像
'extensions' => 'jpeg, jpg, png', // 可接受上传的文件扩展名列表
'mimeTypes' => 'image/jpeg, image/png', // 可接受上传的 MIME 类型列表
'minSize' => null, // 上传文件所需最少多少 Byte 的大小
'maxSize' => 1024 * 1024 * 2, // 上传文件所需最多多少 Byte 的大小
'maxFiles' => 2, // 给定属性最多能承载多少个文件
'minWidth' => 50, // 图片的最小宽度
'maxWidth' => 200, // 图片的最大宽度
'minHeight' => 50, // 图片的最小高度
'maxHeight' => 200, // 图片的最大高度
],
],
],
],
],
13、决定再添加一个字段:config,在此参数中包含新建选题表单所需要的一些限制性规则,配置参数的层级尽量控制在 3 级以内(既避免层级过深,且 Rap 文档工具仅支持 4 级)。后端的参数配置文件,可基于 Rancher 环境变量进行配置覆盖,继而可影响客户端。编辑动作方法文件:api/rests/plan/NewAction.php
$assetUpload = Yii::$app->params['pcsApi']['asset']['upload'];
$data['config']['asset_upload'] = [
'extensions' => $assetUpload['extensions'] ?? '',
'mime_types' => $assetUpload['mimeTypes'] ?? '',
'min_size' => $assetUpload['minSize'] ?? 0,
'max_size' => $assetUpload['maxSize'] ?? 0,
'max_files' => $assetUpload['maxFiles'] ?? 1,
];
"config": {
"asset_upload": {
"extensions": "ogg, pdf, xml, zip, gz, mp4, mp3, wav, webm, gif, jpeg, jpg, png, webp, svg, svgz, tiff, css, csv, txt, vcf, vcard, mov, qt, mkv, mk3d, mka, mks, wmv, flv",
"mime_types": "application/ogg, application/pdf, application/xml, application/zip, application/gzip, audio/mp4, audio/mpeg, audio/ogg, audio/vnd.wave, audio/webm, image/gif, image/jpeg, image/png, image/webp, image/svg+xml, image/tiff, text/css, text/csv, text/plain, text/vcard, text/xml, video/mpeg, video/mp4, video/ogg, video/quicktime, video/webm, video/x-matroska, video/x-ms-wmv, video/x-flv",
"min_size": 0,
"max_size": 1073741824,
"max_files": 10
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/250633.html
