In Yii 2.0, add a new RESTful API for the implementation of new resources (rendering form data)
1. Check REST/ActiveController.php to find the default action method list
/**
* {@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 provides the following actions by default:
index:按页列出资源
view:返回指定资源的详情
create:创建新的资源
update:更新一个存在的资源
delete:删除指定的资源
options:返回支持的 HTTP 方法
3. There is a new requirement, which has been reflected in the prototype. When the tenant setting – the urgency of the topic is closed, in the new topic selection page, the fields: the urgency of the topic selection is not displayed;, when the tenant setting – When the urgency of the topic selection is open, in the new topic selection page, the field: the urgency of the topic selection is displayed, as shown in Figure 1
4. In the current implementation, the RESTful API only provides 3 interfaces, namely:
create:创建新的资源
edit:编辑一个存在的资源(获取表单数据)
update:更新一个存在的资源
5. Therefore, it is decided to add a new interface, new: create a new resource (get the form data), the action method is named: new, the reference source is wordpress, the previous action method: edit, also refer to WordPress, as shown in Figure 2
new:新建新的资源(获取表单数据)
6. Create a new action method file: api/rests/plan/newaction.php
* @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. Get in Postman:http://api.pcs-api.localhost/v1/plans/new, the response parameters, as shown in Figure 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. The default values of some fields are included in the response parameters. After receiving the response data, the front-end and mobile terminals can render the form data based on them to ensure the consistency of the default values of the front-end and mobile terminals, and the default value is controlled by the interface. When the default value needs to be adjusted, it is more flexible. When there is no default value in a field, it is not assigned as: null, because if the value is: null, the field type cannot be fixed or not changed. Finally, the values based on the field types are: empty string, 0, and empty array. However, when the type of a field is a number and its value is 0, the client cannot know whether a field has a default value.
9. Decide to add another field: default_fields to identify whether the value of a field is the default value. Edit action method file: api/rests/plan/newaction.php
* @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. Get in Postman:http://api.pcs-api.localhost/v1/plans/new, the response parameters, as shown in Figure 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. Whether the field is displayed, there are 2 schemes in the design, the first scheme is: in the response parameter, Emergency can exist | does not exist; the second scheme is: in the response parameter, Emergency always exists, and then displayable_fields[’emergency’]Set its value to 1|0. It was finally decided to use the second option. The reason is to ensure that the number and type of the response parameters are unchanged, so as to avoid the client’s judgment processing for whether the field exists, and reduce the complexity of the client judgment processing.
12. When uploading the topic selection material, the list of acceptable uploaded files of the front-end resources is configured by the front-end, and the interface is implemented based on the convention. However, the disadvantage is that once the back-end has For adjustment, the front end also needs to be adjusted accordingly, otherwise it will be inconsistent. Now it is decided to add: config in the response parameter, which contains some restrictive rules required for the new topic selection form. View the parameter configuration file: 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. Decide to add another field: config, this parameter contains some restrictive rules required for the new topic selection form, and the hierarchy of the configuration parameters should be controlled within 3 levels as much as possible (the hierarchy is avoided, and the RAP document tool only supports 4 level). The parameter configuration file of the backend can be configured and overwritten based on the Rancher environment variable, which can then affect the client. Edit action method file: 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
}
}



