POST – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Sun, 31 May 2026 03:49:30 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 在 Yii2 的 GridView::widget 中,’data-method’ => ‘post’ ,请求方式是 GET 的排查分析 https://www.shuijingwanwq.com/2025/08/22/9278/ https://www.shuijingwanwq.com/2025/08/22/9278/#respond Fri, 22 Aug 2025 01:37:38 +0000 endBody()]]> https://www.shuijingwanwq.com/?p=9278 Post Views: 65

1、在 Yii2 的 GridView::widget 中,’data-method’ => ‘post’ ,请求方式是 GET。



 $dataProvider,
	'tableOptions' => ['class' => 'table table-centered table-nowrap table-striped mb-0'],
	'rowOptions' => function ($model, $key, $index, $grid) {
		return ['id' => "tr_{$key}"];
	},
	'options' => [
		'id' => 'grid',
		'class' => 'grid-view',
		'style' => "position: relative; overflow: auto; width: 100%;"
	],
	'filterModel' => $searchModel,
	'columns' => [
		['class' => 'yii\grid\SerialColumn'],
	
		
		[
			'class' => 'yii\grid\ActionColumn',
			'template' => '{messages} {abort}',
			'buttons' => [
				'abort' => function ($url, $model, $key) {
					if ($model->state == PhoneMessageTask::STATE_WAIT || $model->state == PhoneMessageTask::STATE_WAITING_FOR_SENDING) {
						return Html::a('', [
							'abort',
							'id' => $model->id
						], [
							'class' => 'action-icon remark-btn',
							'title' => '中止',
							'data-confirm' => '确定要中止该任务吗?',
							'data-method' => 'post',
						]);
					}
					return null;
				},
			],
		],//end ActionColumn
	],
	'emptyText' => '暂无信息', //没有数据时显示的信息
	'emptyTextOptions' => ['style' => 'text-align:center;'], //没有数据时显示信息的样式设置
	'showOnEmpty' => true, //没有数据时是否显示表格
	'summary' => '共{totalCount}条信息,共{pageCount}页,当前{begin}-{end}条',
	'pager' => [
		'options' => ['class' => 'hidden']
	]
]);
?>


2、后来发现原因在于 yii.js 未加载。但是布局文件中是存在 AppAsset::register($this);


<?php
 
namespace management\assets;
 
use yii\web\AssetBundle;
 
/**
 * Main management application asset bundle.
 */
class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
    ];
    public $js = [
    ];
    public $depends = [
        'yii\web\YiiAsset',
        // 'yii\bootstrap4\BootstrapAsset',
    ];
}
 

3、最后发现原因在于布局文件中不存在

<?php $this->endBody() ?>
]]>
https://www.shuijingwanwq.com/2025/08/22/9278/feed/ 0
基于 Bootstrap File Input v4.3.2 上传文件时,新增 POST 参数的实现 https://www.shuijingwanwq.com/2021/09/26/5301/ https://www.shuijingwanwq.com/2021/09/26/5301/#respond Sun, 26 Sep 2021 11:46:55 +0000 https://www.shuijingwanwq.com/?p=5301 Post Views: 101 1、Bootstrap File Input 是一款非常优秀的HTML5文件上传插件,支持文件预览、多选等一系列特性。基于 Bootstrap File Input v4.3.2 上传文件时,现有参数:upfile、file_id。如图1
Bootstrap File Input 是一款非常优秀的HTML5文件上传插件,支持文件预览、多选等一系列特性。基于 Bootstrap File Input v4.3.2 上传文件时,现有参数:upfile、file_id。

图1

2、现在需要新增参数:type,基于单选按钮的选择:视频、音频,设置其对应值:video、audio。如图2
现在需要新增参数:type,基于单选按钮的选择:视频、音频,设置其对应值:video、audio。

图2

3、参考官网:http://www.bootstrap-fileinput.com/options.html 。配置项:uploadExtraData,将作为数据通过 POST 传递给 url/AJAX 服务器调用的额外数据。 此属性仅适用于 ajax 上传,并且当您为 uploadUrl 设置了值时。如图3
参考官网:http://www.bootstrap-fileinput.com/options.html 。配置项:uploadExtraData,将作为数据通过 POST 传递给 url/AJAX 服务器调用的额外数据。 此属性仅适用于 ajax 上传,并且当您为 uploadUrl 设置了值时。

图3

4、编辑 JS 代码,添加:uploadExtraData: {type: ‘video’},。如图4
编辑 JS 代码,添加:uploadExtraData: {type: 'video'},。

图4



    function initUploadMediaFile(id, type) {
        var container = $('body');
        if (id) {
            container = $(id);
        }
        var uploadFiles = container.find('input[data-target="uploadMediaFile"]');
        $.each(uploadFiles, function (i, v) {
            $_self = $(v);
            var initialPreview = [];
            var initialPreviewConfig = [];
            var previewImage = $('input[name="' + $_self.attr('data-for') + '"]').attr('data-preview') || $('input[name="' + $_self.attr('data-for') + '"]').val();

            if (previewImage) {
                initialPreview.push(previewImage);
                initialPreviewConfig.push({key: getFileName(previewImage)})
            }
            var maxFileSize = 512000;
            var msgSizeTooLargeUnit = '512000KB';
            $_self.fileinput({
                allowedFileTypes: ['video', 'audio'],
                language: 'zh',
                initialPreview: initialPreview,
                initialPreviewConfig: initialPreviewConfig,
                showPreview: false,
                deleteUrl: '',
                // initialPreviewAsData: true,
                multiple: false,
                maxFileSize: maxFileSize,
                msgSizeTooLarge: '建议上传不超过' + msgSizeTooLargeUnit + '大小的图像!',
                allowedFileExtensions: ["'" + type + "'"],
                uploadUrl: "/web-api/vms/upload",
                uploadExtraData: {type: 'video'},
                overwriteInitial: true,
                dropZoneEnabled: false,
                showUpload: false, //是否显示上传按钮
                uploadAsync: true
            }).on("filebatchselected", function(event, files) {
                $(this).fileinput("upload");
            }).on('fileuploaded', function (event, data, previewId, index) {
                $.isLoading('hide');
                if (data.response.code == 0) {
                    // alert(JSON.stringify(data));
                    if (typeof window.uploadFilesSuccess !== 'undefined') {
                        window.uploadFilesSuccess(data.response.id, $(event.target).attr('data-for'));
                    }
                    // $('#'+previewId).attr('data-code',getFileName(data.response.result.attachment));
                    // $('input[name="'+$(event.target).attr('data-for')+'"]').val(data.response.result.original);
                    $('#' + previewId).attr('data-code', getFileName(data.response.id));
                    $('input[name="' + $(event.target).attr('data-for') + '"]').val(data.response.id);
                } else {
                    utils.showNotification('上传文件失败', 3);
                }
            }).on('filecleared', function (event) {
                // console.log(event, 1);
                $('input[name="' + $(event.target).attr('data-for') + '"]').val('');
            }).on('iledeleted', function (event, key) {
                $('input[name="' + $(event.target).attr('data-for') + '"]').val('');
            }).on('filereset', function (event) {
                $('input[name="' + $(event.target).attr('data-for') + '"]').val('');
            }).on('filepreupload', function (event) {
                $('.kv-upload-progress').show();
                $.isLoading({text: '数据提交中,请稍后。。。'});
            }).on('filesuccessremove', function (event, id) {
                $('input[name="' + $(event.target).attr('data-for') + '"]').val('');
            }).on('fileuploaderror', function (event, data, msg) {
                $.isLoading('hide');
                $('.kv-upload-progress').hide();
                utils.showNotification('上传文件失败', 3);
            });
        })
    }


5、测试功能,上传文件时,新增 POST 参数 ( type: video ) 成功实现。如图5
测试功能,上传文件时,新增 POST 参数 ( type: video ) 成功实现。

图5

6、在调整此函数时,基于单选按钮的选择,再增加一个函数参数 $type 就可以实现预期的文件类型的效果。function initUploadMediaFile(id, type, filetype) 。符合预期。如图6
在调整此函数时,基于单选按钮的选择,再增加一个函数参数 $type 就可以实现预期的文件类型的效果。function initUploadMediaFile(id, type, filetype) 。符合预期。

图6

]]>
https://www.shuijingwanwq.com/2021/09/26/5301/feed/ 0
在 Yii 2.0 的 RESTful APIs 中,跨域资源共享的实现 https://www.shuijingwanwq.com/2020/06/09/4233/ https://www.shuijingwanwq.com/2020/06/09/4233/#respond Tue, 09 Jun 2020 06:59:49 +0000 https://www.shuijingwanwq.com/?p=4233 Post Views: 129

1、在域名:http://editorweb.wjdev.chinamcloud.cn 中请求接口:http://api.pcs.wjdev.chinamcloud.cn/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2 ,响应 404 ,所请求的资源上不存在“ Access-Control-Allow-Origin”标头。如图1

在域名:http://editorweb.wjdev.chinamcloud.cn 中请求接口:http://api.pcs.wjdev.chinamcloud.cn/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2 ,响应 404 ,所请求的资源上不存在“ Access-Control-Allow-Origin”标头。

图1


OPTIONS http://api.pcs.wjdev.chinamcloud.cn/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2 404 (Not Found) Access to fetch at 'http://api.pcs.wjdev.chinamcloud.cn/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2' from origin 'http://editorweb.wjdev.chinamcloud.cn' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.


2、决定先在本地环境中自行实现一个前端的 Ajax 请求示例

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%3E%0A%20%20%20%20%24.post(%22http%3A%2F%2Fapi.pcs-api.localhost%2Fv1%2Fplan-tasks%2F88%3Flogin_id%3D2e368664c41b8bf511bcc9c65d86dbc3%26login_tid%3Db26398238620e8cd15b0155cd7aee9b2%22%2C%20%7B%7D%2C%0A%20%20%20%20%20%20%20%20function(data)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20console.log(data.code)%3B%0A%20%20%20%20%20%20%20%20%7D%2C%20%22json%22)%3B%0A%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" />
 

3、POST 请求,响应 200,但是无响应数据。如图2

POST 请求,响应 200,但是无响应数据。

图2


Access to XMLHttpRequest at 'http://api.pcs-api.localhost/v1/plan-tasks/88?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2' from origin 'http://www.pcs-api.localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
jquery.js:9837 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://api.pcs-api.localhost/v1/plan-tasks/88?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=b26398238620e8cd15b0155cd7aee9b2 with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.


4、参考跨域资源共享 CORS 机制:https://www.yiiframework.com/doc/guide/2.0/zh-cn/structure-filters#cors ,将 Cross-Origin Resource Sharing 过滤器添加到控制器


    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        $behaviors = parent::behaviors();

        // remove authentication filter
        $auth = $behaviors['authenticator'];
        unset($behaviors['authenticator']);

        // add CORS filter
        $behaviors['corsFilter'] = [
            'class' => Cors::className(),
        ];

        // re-add authentication filter
        $behaviors['authenticator'] = $auth;
        // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
        $behaviors['authenticator']['except'] = ['options'];

        return $behaviors;
    }


5、再次 POST 请求,响应 200,浏览器中的控制台成功输出响应数据的 code。如图3、图4

再次 POST 请求,响应 200,浏览器中的控制台成功输出响应数据的 code。

图3

 

再次 POST 请求,响应 200,有响应数据

图4

6、因此,需要编辑器的前端有所调整,调整为与 Ajax 的请求示例一致。Content-Type 的值从:application/json 调整为:application/x-www-form-urlencoded。终于服务端接受到请求数据,且响应 200。响应 200 的请求日志数据。如图5

因此,需要编辑器的前端有所调整,调整为与 Ajax 的请求示例一致。Content-Type 的值从:application/json 调整为:application/x-www-form-urlencoded。终于服务端接受到请求数据,且响应 200。

图5


[
    'url' => '/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&amp;login_tid=82c3f78c73c01c92b41a90f6b8b88efd',
    'request_query_params' => [
        'id' => '274',
        'login_id' => '2e368664c41b8bf511bcc9c65d86dbc3',
        'login_tid' => '82c3f78c73c01c92b41a90f6b8b88efd',
    ],
    'request_body_params' => [
        '{"id":274,"queryParam":"eyJ0YXNrSWQiOjI3NCwiY2FsbGJhY2tGbGFnIjoiWSIsImNhbGxiYWNrVXJsIjoiaHR0cDovL2FwaS5wY3Mud2pkZXYuY2hpbmFtY2xvdWQuY24vdjEvcGxhbi10YXNrLXJlc291cmNlcy9jYWxsYmFjaz9sb2dpbl9pZD0yZTM2ODY2NGM0MWI4YmY1MTFiY2M5YzY1ZDg2ZGJjMyZsb2dpbl90aWQ9ODJjM2Y3OGM3M2MwMWM5MmI0MWE5MGY2YjhiODhlZmQiLCJlZGl0b3JfdHlwZSI6IjIiLCJlZGl0b3JfdGl0bGUiOiLmkrDlhpnkvpvnqL8tMjAyMDA1MjgtMiIsImVkaXRvcl9pZCI6Mjc0LCJlZGl0b3JfY2FsbGJhY2tfdXJsIjoiaHR0cDovL2FwaS5wY3Mud2pkZXYuY2hpbmFtY2xvdWQuY24vdjEvcGxhbi10YXNrcy8yNzQ/bG9naW5faWQ9MmUzNjg2NjRjNDFiOGJmNTExYmNjOWM2NWQ4NmRiYzMmbG9naW5fdGlkPTgyYzNmNzhjNzNjMDFjOTJiNDFhOTBmNmI4Yjg4ZWZkIiwiZGF0YSI6eyJzb3VyY2UiOiJjaGluYW1jbG91ZF9zY21zIiwiY3VycmVudF9zdGVwX2NvZGUiOiJ3cml0ZV9mZWVkIiwib2JqZWN0X3R5cGUiOiJmZWVkIiwiYXJ0aWNsZV90eXBlX2lkIjoxfX0' => '"}',
    ],
    'user_id' => '3',
    '$_SERVER' => [
        'HTTP_ACCEPT_LANGUAGE' => 'zh-CN,zh;q=0.9',
        'HTTP_ACCEPT' => 'application/json,text/plain, */*',
        'HTTP_HOST' => 'api.pcs.wjdev.chinamcloud.cn',
        'REMOTE_ADDR' => '10.42.22.22',
        'REQUEST_URI' => '/v1/plan-tasks/274?login_id=2e368664c41b8bf511bcc9c65d86dbc3&amp;login_tid=82c3f78c73c01c92b41a90f6b8b88efd',
        'REQUEST_METHOD' => 'POST',
        'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
    ],
]


]]>
https://www.shuijingwanwq.com/2020/06/09/4233/feed/ 0
在 Yii 2.0 的 RESTful APIs 中,view:返回指定资源的详情,HTTP 动词同时支持 GET 与 POST 的实现 https://www.shuijingwanwq.com/2020/06/05/4221/ https://www.shuijingwanwq.com/2020/06/05/4221/#respond Fri, 05 Jun 2020 02:31:12 +0000 'view']]> 'view']]> https://www.shuijingwanwq.com/?p=4221 Post Views: 103

1、在 Postman 中 GET 请求指定资源的详情,响应 200,如图1

在 Postman 中 GET 请求指定资源的详情,响应 200

图1

2、查看路由配置,代码如下


        /* 任务管理 */
        [
            'class' => 'yii\rest\UrlRule',
            'controller' => ['v1/plan-task'],
            'only' => [
                'log-create',
                'index',
                'have',
                'export',
                'have-export',
                'create',
                'view',
                'update',
                'claim',
                'delete',
                'finish',
                'transfer',
                'video-edit',
                'write',
                'write-feed',
                'commit-article',
                'article-review',
                'disable',
                'upload',
                'enable',
                'edit'
            ],
            'tokens' => ['{id}' => ''],
            'extraPatterns' => [
                'GET have' => 'have',
                'GET export' => 'export',
                'GET have-export' => 'have-export',
                'PUT claim/{id}' => 'claim',
                'PUT finish/{id}' => 'finish',
                'POST log/{id}' => 'log-create',
                'GET {id}' => 'view',
                'GET edit/{id}' => 'edit',
                'PUT update' => 'update',
                'PUT transfer/{id}' => 'transfer',
                'GET video-edit/{id}' => 'video-edit',
                'GET write/{id}' => 'write',
                'GET write-feed/{id}' => 'write-feed',
                'GET commit-article/{id}' => 'commit-article',
                'GET article-review/{id}' => 'article-review',
                'PUT disable/{id}' => 'disable',
                'GET upload/{id}' => 'upload',
                'PUT enable/{id}' => 'enable',
            ],
        ],


3、查看控制器,代码如下

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2018/05/05
 * Time: 11:43
 */
 
namespace api\controllers;
 
use yii\rest\ActiveController;
 
class PlanTaskController extends ActiveController
{
    public $serializer = [
        'class' => 'api\rests\plan_task\Serializer',
        'collectionEnvelope' => 'items',
    ];
     
    /**
     * @inheritdoc
     */
    public function actions()
    {
        $actions = parent::actions();
        // 禁用"options"动作
        unset($actions['options']);
        $actions['index']['class'] = 'api\rests\plan_task\IndexAction';
        $actions['create']['class'] = 'api\rests\plan_task\CreateAction';
        $actions['view']['class'] = 'api\rests\plan_task\ViewAction';
        $actions['update']['class'] = 'api\rests\plan_task\UpdateAction';
        $actions['delete']['class'] = 'api\rests\plan_task\DeleteAction';
        $actions['have'] = [
            'class' => 'api\rests\plan_task\HaveAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['export'] = [
            'class' => 'api\rests\plan_task\ExportAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['have-export'] = [
            'class' => 'api\rests\plan_task\HaveExportAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['edit'] = [
            'class' => 'api\rests\plan_task\EditAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['claim'] = [
            'class' => 'api\rests\plan_task\ClaimAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['finish'] = [
            'class' => 'api\rests\plan_task\FinishAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['transfer'] = [
            'class' => 'api\rests\plan_task\TransferAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['video-edit'] = [
            'class' => 'api\rests\plan_task\VideoEditAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['write'] = [
            'class' => 'api\rests\plan_task\WriteAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['write-feed'] = [
            'class' => 'api\rests\plan_task\WriteFeedAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['commit-article'] = [
            'class' => 'api\rests\plan_task\CommitArticleAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['article-review'] = [
            'class' => 'api\rests\plan_task\ArticleReviewAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['disable'] = [
            'class' => 'api\rests\plan_task\DisableAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['upload'] = [
            'class' => 'api\rests\plan_task\UploadAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['enable'] = [
            'class' => 'api\rests\plan_task\EnableAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['log-create'] = [
            'class' => 'api\rests\plan_task\LogCreateAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
        $actions['status-count'] = [
            'class' => 'api\rests\plan_task\StatusCountAction',
            'modelClass' => $this->modelClass,
            'checkAccess' => [$this, 'checkAccess'],
        ];
 
        return $actions;
    }
}
 

4、在 Postman 中 POST 请求指定资源的详情,响应 404,如图2

在 Postman 中 POST 请求指定资源的详情,响应 404

图2


{
    "name": "Not Found",
    "message": "页面未找到。",
    "code": 0,
    "status": 404,
    "type": "yii\\web\\NotFoundHttpException"
}


5、调整路由配置,GET /plan-tasks/79 和 POST /plan-tasks/79:返回资源ID为 79 的详细信息


'GET,POST {id}' => 'view',


6、在 Postman 中 POST 请求指定资源的详情,响应 405,不允许的方法。该 URL 仅可以处理以下请求方法:GET,HEAD。如图3

在 Postman 中 POST 请求指定资源的详情,响应 405,不允许的方法。该 URL 仅可以处理以下请求方法:GET,HEAD

图3


{
    "name": "Method Not Allowed",
    "message": "Method Not Allowed. This URL can only handle the following request methods: GET, HEAD.",
    "code": 0,
    "status": 405,
    "type": "yii\\web\\MethodNotAllowedHttpException"
}


7、查看日志,在过滤器 verbFilter:支持 HTTP 方法验证 处验证失败,如图4

查看日志,在过滤器 verbFilter:支持 HTTP 方法验证 处验证失败

图4


yii\web\MethodNotAllowedHttpException: Method Not Allowed. This URL can only handle the following request methods: GET, HEAD. in E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\filters\VerbFilter.php:105
Stack trace:
#0 [internal function]: yii\filters\VerbFilter->beforeAction(Object(yii\base\ActionEvent))
#1 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\base\Component.php(627): call_user_func(Array, Object(yii\base\ActionEvent))
#2 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\base\Controller.php(276): yii\base\Component->trigger('beforeAction', Object(yii\base\ActionEvent))
#3 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\web\Controller.php(188): yii\base\Controller->beforeAction(Object(api\rests\plan_task\ViewAction))
#4 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\base\Controller.php(155): yii\web\Controller->beforeAction(Object(api\rests\plan_task\ViewAction))
#5 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\base\Module.php(528): yii\base\Controller->runAction('view', Array)
#6 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\web\Application.php(103): yii\base\Module->runAction('v1/plan-task/vi...', Array)
#7 E:\wwwroot\pcs-api-feature-php-7.4\vendor\yiisoft\yii2\base\Application.php(386): yii\web\Application->handleRequest(Object(yii\web\Request))
#8 E:\wwwroot\pcs-api-feature-php-7.4\api\web\index.php(17): yii\base\Application->run()
#9 {main}


8、在控制器中覆盖 yii\rest\ActiveController 的 verbs 方法,添加对于 POST 的支持


    /**
     * {@inheritdoc}
     */
    protected function verbs()
    {
        $verbs = parent::verbs();
        $verbs['view'] = ['GET', 'HEAD', 'POST'];
        return $verbs;
    }


9、在 Postman 中 GET 或者 POST 请求指定资源的详情,响应 200,如图5

在 Postman 中 GET 或者 POST 请求指定资源的详情,响应 200

图5

]]>
https://www.shuijingwanwq.com/2020/06/05/4221/feed/ 0
在 Windows PowerShell 中执行命令:curl -X POST –data,报错:Invoke-WebRequest : 找不到接受实际参数“POST”的位置形式参数。的分析解决 https://www.shuijingwanwq.com/2018/12/28/3077/ https://www.shuijingwanwq.com/2018/12/28/3077/#respond Fri, 28 Dec 2018 07:45:25 +0000 http://www.shuijingwanwq.com/?p=3077 Post Views: 489 1、在 Windows PowerShell 中执行命令:curl -X POST –data,报错:Invoke-WebRequest : 找不到接受实际参数“POST”的位置形式参数。如图1
在 Windows PowerShell 中执行命令:curl -X POST --data,报错:Invoke-WebRequest : 找不到接受实际参数“POST”的位置形式参数。

图1



PS E:\wwwroot\channel-pub-api> curl -X POST --data "access_token=2.00VtCfGEXWOOKE229f72fa42wkzKAE" https://api.weibo.com
/oauth2/get_token_info
Invoke-WebRequest : 找不到与参数名称“X”匹配的参数。
所在位置 行:1 字符: 6
+ curl -X POST --data "access_token=2.00VtCfGEXWOOKE229f72fa42wkzKAE" h ...
+      ~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-WebRequest],ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.InvokeWebRequestCommand



2、Invoke-WebRequest 是在 Windows 平台上类似于 cURL 的命令行工具,执行命令:Get-Help Invoke-WebRequest,如图2
Invoke-WebRequest 是在 Windows 平台上类似于 cURL 的命令行工具,执行命令:Get-Help Invoke-WebRequest

图2

<pre class="wp-block-syntaxhighlighter-code">

PS E:\wwwroot\channel-pub-api> Get-Help Invoke-WebRequest

是否要运行 Update-Help?
Update-Help cmdlet 下载 Windows PowerShell 模块的最新帮助文件,并将其安装在你的计算机上。有关
Update-Help cmdlet 的详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkId=210614。
[Y] 是(Y)  [N] 否(N)  [S] 暂停(S)  [?] 帮助 (默认值为“Y”):

名称
    Invoke-WebRequest

摘要
    Gets content from a web page on the Internet.


语法
    Invoke-WebRequest [-Uri] <Uri> [-Body <Object>] [-Certificate <X509Certificate>] [-CertificateT
    [-ContentType <String>] [-Credential <PSCredential>] [-DisableKeepAlive] [-Headers <IDictionary
    ] [-MaximumRedirection <Int32>] [-Method {Default | Get | Head | Post | Put | Delete | Trace |
    tch}] [-OutFile <String>] [-PassThru] [-Proxy <Uri>] [-ProxyCredential <PSCredential>] [-ProxyU
    ] [-SessionVariable <String>] [-TimeoutSec <Int32>] [-TransferEncoding {chunked | compress | de
    ity}] [-UseBasicParsing] [-UseDefaultCredentials] [-UserAgent <String>] [-WebSession <WebReques
    arameters>]


说明
    The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web ser
    response and returns collections of forms, links, images, and other significant HTML elements.

    This cmdlet was introduced in Windows PowerShell 3.0.


相关链接
    Online Version: http://go.microsoft.com/fwlink/?LinkId=821826
    Invoke-RestMethod
    ConvertFrom-Json
    ConvertTo-Json

备注
    若要查看示例,请键入: "get-help Invoke-WebRequest -examples".
    有关详细信息,请键入: "get-help Invoke-WebRequest -detailed".
    若要获取技术信息,请键入: "get-help Invoke-WebRequest -full".
    有关在线帮助,请键入: "get-help Invoke-WebRequest -online"



</pre>
3、参考帮助文档,调整命令,执行命令,请求成功,如图3
参考帮助文档,调整命令,执行命令,请求成功

图3



PS E:\wwwroot\channel-pub-api> curl -Uri 'https://api.weibo.com/oauth2/get_token_info' -Body 'access_token=2.00VtCfGEXWO
OKE229f72fa42wkzKAE' -Method 'POST'


StatusCode        : 200
StatusDescription : OK
Content           : {"uid":3762971921,"appkey":"3815687113","scope":"","create_at":1545898005,"expire_in":44817}
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    Pragma: No-cache
                    Content-Length: 92
                    Cache-Control: no-cache
                    Content-Type: application/json;charset=UTF-8
                    Date: Fri, 28 Dec 2018 06:33:02 GMT
                    Expires: Thu,...
Forms             : {}
Headers           : {[Connection, keep-alive], [Pragma, No-cache], [Content-Length, 92], [Cache-Control, no-cache]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 92




]]>
https://www.shuijingwanwq.com/2018/12/28/3077/feed/ 0
在 Yii 2.0 上,RESTful 风格的 Web Service 服务的 API,POST 批量新建资源的实现 https://www.shuijingwanwq.com/2018/05/16/2644/ https://www.shuijingwanwq.com/2018/05/16/2644/#respond Wed, 16 May 2018 07:33:19 +0000 http://www.shuijingwanwq.com/?p=2644 Post Views: 74 1、\api\rests\plan_task\CreateAction.php,具体实现可参考网址:https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/input-tabular-input.md ,代码如下:
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\plan_task;

use Yii;
use yii\base\Model;
use yii\helpers\Url;
use yii\web\ServerErrorHttpException;

/**
 * CreateAction implements the API endpoint for creating a new model from the given data.
 *
 * 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;


    /**
     * 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);
        }

        // 当前用户的身份实例,未认证用户则为 Null
        $identity = Yii::$app->user->identity;

        /* @var $model \yii\db\ActiveRecord */
        /*
        $model = new $this->modelClass([
            'scenario' => 'create',
        ]);
        */

        $requestParams = Yii::$app->getRequest()->getBodyParams();

        $count = count($requestParams);
        //创建一个初始的 $models 数组包含一个默认的模型
        $scenario = 'create';
        $models = [new $this->modelClass([
            'scenario' => $scenario,
        ])];
        for($i = 1; $i < $count; $i++) {
            $models[] = new $this->modelClass([
                'scenario' => $scenario,
            ]);
        }

        // 批量填充模型属性
        if (!Model::loadMultiple($models, $requestParams, '')) {
            return ['code' => 20010, 'message' => Yii::t('error', '20010')];
        }

        foreach ($models as $key => $model) {
            $model->group_id = $identity->group_id;
            $model->config_column_id = $model->plan['config_column_id'];
            $model->create_user_id = $identity->id;
            $model->create_name = $identity->login_name;
            $model->exec_name = $model->userByExecUserId['login_name'];
            $model->task_data = serialize([]);
            $model->ended_at = time() + Yii::$app->params['planTaskExpire'];
            $models[$key] = $model;
        }

        // 批量验证模型
        if (Model::validateMultiple($models)) {
            foreach ($models as $model) {
                $model->save(false);
            }
            $response = Yii::$app->getResponse();
            $response->setStatusCode(201);
        } else {
            return ['code' => 20011, 'message' => Yii::t('error', '20011')];
        }

        return ['code' => 10000, 'message' => Yii::t('success', '10006'), 'data' => ['items' => $models]];
    }
}


</pre>
2、在 Postman 上,请求参数如图1


0[plan_id]:1
0[title]:早间新闻的标题1下的任务7
0[config_task_id]:2
0[exec_user_id]:8
0[place]:早间新闻的标题1下的地点7
0[task_info]:早间新闻的标题1下的内容7
1[plan_id]:1
1[title]:早间新闻的标题1下的任务8
1[config_task_id]:2
1[exec_user_id]:8
1[place]:早间新闻的标题1下的地点8
1[task_info]:早间新闻的标题1下的地点8


在 Postman 上,请求参数

图1

3、应前端的请求,添加表单名称,\api\rests\plan_task\CreateAction.php,代码如下
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\plan_task;

use Yii;
use yii\base\Model;
use yii\helpers\Url;
use yii\web\ServerErrorHttpException;

/**
 * 指派(创建任务)
 *
 * 1、请求参数列表
 * (1)plan_id 必填,选题ID
 * (2)title 必填,任务标题
 * (3)config_task_id 必填,任务配置(类型)ID
 * (4)exec_user_id 必填,执行用户ID
 * (5)place 必填,地点
 * (6)task_info 必填,任务信息
 *
 * 2、输入数据验证规则
 * (1)必填:plan_id, title, config_task_id, exec_user_id, place, task_info;
 * (2)存在性:config_task_id 必须存在于任务配置模型中,且其状态为 1:启用;
 * (3)存在性:plan_id 必须存在于选题模型中,且其状态为 3:通过/5:指派;
 * (4)存在性:plan_id 选题所属栏目ID必须存在,且其状态为 1:启用;
 * (5)存在性:create_user_id 必须存在于选题所属栏目的人员配置模型中,且其状态为 1:启用;
 * (6)存在性:exec_user_id 必须存在于选题所属栏目的人员配置模型中,且其状态为 1:启用;
 * (7)默认值(''):'place', 'task_info';
 *
 * 3、操作数据(事务)
 * (1)循环插入任务(传递 false 作为 [[save()]]的一个参数使其不会重复验证两次);
 * (2)批量插入任务步骤,创建批量 INSERT 命令(batchInsert);
 * (3)更新选题状态:指派;
 *
 * 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;


    /**
     * 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);
        }

        // 当前用户的身份实例,未认证用户则为 Null
        $identity = Yii::$app->user->identity;

        /* @var $model \yii\db\ActiveRecord */
        /*
        $model = new $this->modelClass([
            'scenario' => 'create',
        ]);
        */

        $requestParams = Yii::$app->getRequest()->getBodyParams();

        $formName = 'plan_task';
        $count = count($requestParams[$formName]);
        //创建一个初始的 $models 数组包含一个默认的模型
        $scenario = 'create';
        $models = [new $this->modelClass([
            'scenario' => $scenario,
        ])];
        for($i = 1; $i < $count; $i++) {
            $models[] = new $this->modelClass([
                'scenario' => $scenario,
            ]);
        }

        // 批量填充模型属性
        if (!Model::loadMultiple($models, $requestParams, $formName)) {
            return ['code' => 20010, 'message' => Yii::t('error', '20010')];
        }

        foreach ($models as $key => $model) {
            $model->group_id = $identity->group_id;
            $model->config_column_id = $model->planById['config_column_id'];
            $model->create_user_id = $identity->id;
            $model->create_name = $identity->login_name;
            $model->exec_name = $model->userByExecUserId['login_name'];
            $model->task_data = serialize([]);
            $model->ended_at = time() + Yii::$app->params['planTaskExpire'];
            $models[$key] = $model;
        }

        // 批量验证模型
        if (Model::validateMultiple($models)) {
            $modelResult = $model->createMultiple($models);
            if (!$modelResult) {
                return ['code' => 20015, 'message' => Yii::t('error', '20015')];
            }
            $response = Yii::$app->getResponse();
            $response->setStatusCode(201);
        } else {
            foreach ($models as $model) {
                if ($model->hasErrors()) {
                    $response = Yii::$app->getResponse();
                    $response->setStatusCode(422, 'Data Validation Failed.');
                    foreach ($model->getFirstErrors() as $message) {
                        $firstErrors = $message;
                        break;
                    }
                    return ['code' => 20004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20004'), ['firstErrors' => $firstErrors]))];
                }
            }

            throw new ServerErrorHttpException('Failed to create the object for unknown reason.');
        }

        foreach ($models as $key => $model) {
            $model->task_data = unserialize($model->task_data);
            $models[$key] = $model;
        }

        return ['code' => 10000, 'message' => Yii::t('success', '10006'), 'data' => ['items' => $models]];
    }
}


</pre>
4、\common\logics\PlanTask.php,代码如下


    /**
     * 批量指派(创建任务)
     *
     * @param $models
     *
     * @return bool the saved model or false if saving fails
     * @throws \Throwable
     */
    public function createMultiple($models)
    {
        $transaction = Yii::$app->db->beginTransaction();
        $time = time();
        try {
            foreach ($models as $model) {
                if (!$model->save(false)) {
                    throw new ServerErrorHttpException(Yii::t('error', '20015'), 20015);
                }
                
                /* 创建MySQL模型(选题任务步骤) */
                $table = PlanTaskStep::tableName();
                $columns = [ 'group_id', 'task_id', 'task_title', 'step_code', 'step_name', 'sort_order', 'updated_name', 'created_at', 'updated_at' ];
                /* 将模型记录转换为索引数组 */
                foreach ($model->configTaskSteps as $configTaskStep) {
                    if ($configTaskStep->status == ConfigTaskStep::CONFIG_TASK_STEP_STATUS_ENABLE && $configTaskStep->is_default == 1) {
                        $rows[] = [
                            $model->group_id,
                            $model->id,
                            $model->title,
                            $configTaskStep->step_code,
                            $configTaskStep->step_name,
                            $configTaskStep->sort_order,
                            $model->create_name,
                            $time,
                            $time,
                        ];
                    }
                }
            }
            Yii::$app->db->createCommand()->batchInsert($table, $columns, $rows)->execute();
            $transaction->commit();
            
            return true;
        } catch (\Throwable $e) {
            $transaction->rollBack();
            throw $e;
        }
    }


5、在 Postman 上,请求参数如图2


plan_task[0][plan_id]:2
plan_task[0][title]:选题2的任务6的标题
plan_task[0][config_task_id]:2
plan_task[0][exec_user_id]:187
plan_task[0][place]:选题2的任务6的地点
plan_task[0][task_info]:选题2的任务6的内容
plan_task[1][plan_id]:2
plan_task[1][title]:选题2的任务7的标题
plan_task[1][config_task_id]:2
plan_task[1][exec_user_id]:191
plan_task[1][place]:选题2的任务7的地点
plan_task[1][task_info]:选题2的任务7的内容


在 Postman 上,请求参数

图2

6、在 Postman 上,响应参数如图3


{
    "code": 10000,
    "message": "指派(创建任务)成功",
    "data": {
        "items": [
            {
                "plan_id": "2",
                "title": "选题2的任务6的标题",
                "config_task_id": "2",
                "exec_user_id": "187",
                "place": "选题2的任务6的地点",
                "task_info": "选题2的任务6的内容",
                "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
                "config_column_id": 1,
                "create_user_id": 8,
                "create_name": "13281105967",
                "exec_name": "test3",
                "task_data": "a:0:{}",
                "ended_at": 1529047691,
                "created_at": 1526455691,
                "updated_at": 1526455691,
                "id": 37
            },
            {
                "plan_id": "2",
                "title": "选题2的任务7的标题",
                "config_task_id": "2",
                "exec_user_id": "191",
                "place": "选题2的任务7的地点",
                "task_info": "选题2的任务7的内容",
                "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
                "config_column_id": 1,
                "create_user_id": 8,
                "create_name": "13281105967",
                "exec_name": "test4",
                "task_data": "a:0:{}",
                "ended_at": 1529047691,
                "created_at": 1526455692,
                "updated_at": 1526455692,
                "id": 38
            }
        ]
    }
}


在 Postman 上,响应参数

图3

 ]]>
https://www.shuijingwanwq.com/2018/05/16/2644/feed/ 0
在 Windwos 10、PHP 7.1.12 下 基于 Yii 2 Starter Kit,复制后台应用为接口应用,实现 RESTful Web 服务的流程 https://www.shuijingwanwq.com/2018/01/10/2206/ https://www.shuijingwanwq.com/2018/01/10/2206/#comments Wed, 10 Jan 2018 09:58:51 +0000 http://www.shuijingwanwq.com/?p=2206 Post Views: 126 1、在 Windows PowerShll 中,进入 E:\wwwroot\cmcp-api 目录,如图1
在 Windows PowerShll 中,进入 E:\wwwroot\cmcp-api 目录

图1

2、新建应用api,复制backend目录为api,如图2
新建应用api,复制backend目录为api

图2

3、编辑 \.env.dist,新增 api 相关的配置,此为提交至Git版本控制的配置文件,如图3
<pre class="wp-block-syntaxhighlighter-code">

API_HOST_INFO         = http://api.yii2-starter-kit.dev
#API_HOST_INFO         = http://yii2-starter-kit.dev
#API_BASE_URL          = /api/web
API_COOKIE_VALIDATION_KEY = <generated_key>

</pre>
编辑 \.env.dist,新增 api 相关的配置,此为提交至Git版本控制的配置文件

图3

4、编辑 \.env,新增 api 相关的配置,此为实际生效的配置文件,如图4
<pre class="wp-block-syntaxhighlighter-code">

API_HOST_INFO         = http://www.cmcp-api.localhost
#API_HOST_INFO         = http://yii2-starter-kit.dev
#API_BASE_URL          = /api/web
API_COOKIE_VALIDATION_KEY = <generated_key>

</pre>
编辑 \.env,新增 api 相关的配置,此为实际生效的配置文件

图4

5、编辑 \common\config\bootstrap.php,配置接口应用的别名,如图5


Yii::setAlias('@api', realpath(__DIR__.'/../../api'));
Yii::setAlias('@apiUrl', env('API_HOST_INFO') . env('API_BASE_URL') );


编辑 \common\config\bootstrap.php,配置接口应用的别名

图5

6、编辑 \common\config\base.php,配置接口应用的语言包文件,如图6


'api'=>'api.php',


编辑 \common\config\base.php,配置接口应用的语言包文件

图6

7、新建接口应用的中文语言包文件,复制 \common\messages\zh\backend.php 为 \common\messages\zh\api.php(如果需要支持其他的语言,可以在其他的语言目录下新建),如图7
新建接口应用的中文语言包文件,复制 \common\messages\zh\backend.php 为 \common\messages\zh\api.php(如果需要支持其他的语言,可以在其他的语言目录下新建)

图7

8、编辑 \common\config\base.php,配置接口应用的URL的解析与生成,如图8


        'urlManagerApi' => \yii\helpers\ArrayHelper::merge(
            [
                'hostInfo' => env('API_HOST_INFO'),
                'baseUrl' => env('API_BASE_URL'),
            ],
            require(Yii::getAlias('@api/config/_urlManager.php'))
        ),


编辑 \common\config\base.php,配置接口应用的URL的解析与生成

图8

9、编辑 \console\controllers\AppController.php,搜索此文件有6处backend,则相应复制3份为api,如图9


    public $writablePaths = [
        '@common/runtime',
        '@frontend/runtime',
        '@frontend/web/assets',
        '@backend/runtime',
        '@backend/web/assets',
        '@api/runtime',
        '@api/web/assets',
        '@storage/cache',
        '@storage/web/source'
    ];

    public $executablePaths = [
        '@backend/yii',
        '@api/yii',
        '@frontend/yii',
        '@console/yii',
    ];


编辑 \console\controllers\AppController.php,搜索此文件有6处backend,则相应复制3份为api

图9

10、编辑 \autocompletion.php,新增接口应用相关的配置,如图10


 * @property yii\web\UrlManager $urlManagerApi UrlManager for api application.


编辑 \autocompletion.php,新增接口应用相关的配置

图10

11、在目录api中搜索backend\、backend/、=> ‘backend’、BACKEND,严格匹配大小写,将其分别替换为api\、api/、=> ‘api’、API,如图11


backend\ 替换为: api\
backend/ 替换为: api/
=> 'backend' 替换为: => 'api'
BACKEND 替换为: => API


在目录api中搜索backend\、backend/、=> 'backend'、BACKEND,严格匹配大小写,将其分别替换为api\、api/、=> 'api'、API

图11

12、在 \tests 目录中,还有相应的与新增接口应用相关的配置,此部分暂缓一下,到需要进行自动化测试的时候,再来进行配置了。查看 \api\web\index-test.php,如图12
在 \tests 目录中,还有相应的与新增接口应用相关的配置,此部分暂缓一下,到需要进行自动化测试的时候,再来进行配置了。查看 \api\web\index-test.php

图12

13、在 Windows PowerShll 中,进入 E:\wwwroot\cmcp-api 目录,再次运行命令:php console/yii app/setup,设置可写、可执行权限,如图13
在 Windows PowerShll 中,进入 E:\wwwroot\cmcp-api 目录,再次运行命令:php console/yii app/setup,设置可写、可执行权限

图13

14、在 Nginx 配置文件中新增虚拟主机,重启Nginx,如图14


## API ##
server {
    listen 80; ## 监听 ipv4 上的 80 端口
    # listen [::]:80 default_server ipv6only=on; ## 监听 ipv6 上的 80 端口

    root E:/wwwroot/cmcp-api/api/web;
    index index.php index.html;

    server_name www.cmcp-api.localhost;

    charset utf-8;

	access_log logs/www.cmcp-api.localhost.access.log;
	error_log logs/www.cmcp-api.localhost.error.log;

    client_max_body_size 128M;

    # There is a VirtualBox bug related to sendfile that can lead to
    # corrupted files, if not turned-off on Vagrant based setup
    # sendfile off;

    location / {
		# 如果找不到真实存在的文件,把请求分发至 index.php
        try_files $uri $uri/ /index.php?$args;
    }

    # location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|js)$ {
    #     access_log off;
    #     expires max;
    # }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass php-fpm;
        fastcgi_index index.php;
        include fastcgi_params;
    }

	location ~ /\.(ht|svn|git) {
        deny all;
    }

}


在 Nginx 配置文件中新增虚拟主机,重启Nginx

图14

15、在 hosts 文件中新增配置,如图15


# 内容管控平台接口
127.0.0.1 cmcp-api.localhost www.cmcp-api.localhost frontend.cmcp-api.localhost backend.cmcp-api.localhost storage.cmcp-api.localhost


在 hosts 文件中新增配置

图15

16、打开 http://www.cmcp-api.localhost, 如果出现样式文件加载响应404的情况,可以删除 \api\web\assets 下的所有子目录,如图16
打开 http://www.cmcp-api.localhost, 如果出现样式文件加载响应404的情况,可以删除 \api\web\assets 下的所有子目录

图16

17、准备将创建页面的功能基于接口实现,如图17
准备将创建页面的功能基于接口实现

图17

18、调整 Page 模型的相关结构,实现模型分层,参考网址:https://www.shuijingwanwq.com/2017/08/15/1713/ ,如图18
调整 Page 模型的相关结构,实现模型分层,参考网址:https://www.shuijingwanwq.com/2017/08/15/1713/

图18

19、打开网址:http://frontend.cmcp-api.localhost/gii ,如图19
打开网址:http://frontend.cmcp-api.localhost/gii

图19

20、基于数据库表 ca_page 建立相应模型,如图20
基于数据库表 ca_page 建立相应模型

图20

21、在common目录中新建logics目录,用于MySQL模型的逻辑层所在目录,如图21
在common目录中新建logics目录,用于MySQL模型的逻辑层所在目录

图21

22、复制 \common\models\Page.php 至 \common\logics\Page.php,如图22
<pre class="wp-block-syntaxhighlighter-code">

<?php namespace common\models; use Yii; use yii\behaviors\SluggableBehavior; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; /** * This is the model class for table "page". * * @property integer $id * @property string $slug * @property string $title * @property string $body * @property string $view * @property integer $status * @property integer $created_at * @property integer $updated_at */ class Page extends ActiveRecord { const STATUS_DRAFT = 0; const STATUS_PUBLISHED = 1; /** * @inheritdoc */ public static function tableName() { return '{{%page}}'; } /** * @inheritdoc */ public function behaviors() { return [ TimestampBehavior::className(), 'slug' => [
                'class' => SluggableBehavior::className(),
                'attribute' => 'title',
                'ensureUnique' => true,
                'immutable' => true
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['title', 'body'], 'required'],
            [['body'], 'string'],
            [['status'], 'integer'],
            [['slug'], 'unique'],
            [['slug'], 'string', 'max' => 2048],
            [['title'], 'string', 'max' => 512],
            [['view'], 'string', 'max' => 255]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => Yii::t('common', 'ID'),
            'slug' => Yii::t('common', 'Slug'),
            'title' => Yii::t('common', 'Title'),
            'body' => Yii::t('common', 'Body'),
            'view' => Yii::t('common', 'Page View'),
            'status' => Yii::t('common', 'Active'),
            'created_at' => Yii::t('common', 'Created At'),
            'updated_at' => Yii::t('common', 'Updated At'),
        ];
    }
}


</pre>
复制 \common\models\Page.php 至 \common\logics\Page.php

图22

23、基于 diff ,编辑 \common\logics\Page.php,如图23
基于 diff ,编辑 \common\logics\Page.php

图23

24、在common/logics目录中的MySQL模型文件为业务逻辑相关,继承至 \common\models\Page 数据层,如图24
<pre class="wp-block-syntaxhighlighter-code">

<?php namespace common\logics; use Yii; use yii\behaviors\SluggableBehavior; use yii\behaviors\TimestampBehavior; class Page extends \common\models\Page { const STATUS_DRAFT = 0; const STATUS_PUBLISHED = 1; /** * @inheritdoc */ public function behaviors() { return [ TimestampBehavior::className(), 'slug' => [
                'class' => SluggableBehavior::className(),
                'attribute' => 'title',
                'ensureUnique' => true,
                'immutable' => true
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['title', 'body'], 'required'],
            [['body'], 'string'],
            [['status'], 'integer'],
            [['slug'], 'unique'],
            [['slug'], 'string', 'max' => 2048],
            [['title'], 'string', 'max' => 512],
            [['view'], 'string', 'max' => 255],
        ];
    }

}


</pre>
在common/logics目录中的MySQL模型文件为业务逻辑相关,继承至 \common\models\Page 数据层

图24

25、点击Model Generator下的Start按钮,生成模型Page,命名空间为common\models,此时需支持国际化,覆盖\common\models\Page.php,如图25
点击Model Generator下的Start按钮,生成模型Page,命名空间为common\models,此时需支持国际化,覆盖\common\models\Page.php

图25

26、编辑 \common\config\base.php,当源语言和目标语言相同时,是否强制进行消息翻译,默认为假,设置为真,如图26


                '*'=> [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'forceTranslation' => true,
                    'basePath'=>'@common/messages',
                    'fileMap'=>[
                        'common'=>'common.php',
                        'backend'=>'backend.php',
                        'api'=>'api.php',
                        'frontend'=>'frontend.php',
                    ],
                    'on missingTranslation' => ['\backend\modules\i18n\Module', 'missingTranslation']
                ],


编辑 \common\config\base.php,当源语言和目标语言相同时,是否强制进行消息翻译,默认为假,设置为真

图26

27、新建 \common\messages\en\model\page.php,支持目标语言为英语美国时的消息翻译,如图27


return [
    'ID' => 'ID',
    'Slug' => 'Slug',
    'Title' => 'Title',
    'Body' => 'Body',
    'View' => 'Page View',
    'Status' => 'Active',
    'Created At' => 'Created At',
    'Updated At' => 'Updated At',
];


新建 \common\messages\en\model\page.php,支持目标语言为英语美国时的消息翻译

图27

28、新建 \common\messages\zh\model\page.php,支持目标语言为简体中文时的消息翻译,如图28


return [
    'ID' => 'ID',
    'Slug' => '别名',
    'Title' => '标题',
    'Body' => '内容',
    'View' => '页面浏览',
    'Status' => '活动',
    'Created At' => '创建时间',
    'Updated At' => '更新时间',
];


新建 \common\messages\zh\model\page.php,支持目标语言为简体中文时的消息翻译

图28

29、新建 \api\models\Page.php,在api/models目录中的MySQL模型文件为业务逻辑相关(仅与api相关),继承至 \common\logics\Page 逻辑层,如图29
新建 \api\models\Page.php,在api/models目录中的MySQL模型文件为业务逻辑相关(仅与api相关),继承至 \common\logics\Page 逻辑层

图29

30、复制\api\models\Page.php 至 \frontend\models\Page.php、\backend\models\Page.php,调整为各自的命名空间,如图30
复制\api\models\Page.php 至 \frontend\models\Page.php、\backend\models\Page.php,调整为各自的命名空间

图30

31、在 api 应用中搜索 use common\models\Page;,替换为:use api\models\Page;,在前台、后台应用中同样类似处理,如图31
在 api 应用中搜索 use common\models\Page;,替换为:use api\models\Page;,在前台、后台应用中同样类似处理

图31

32、当本地设置为简体中文时,打开 http://backend.cmcp-api.localhost/page/create ,翻译功能可用,如图32
当本地设置为简体中文时,打开 http://backend.cmcp-api.localhost/page/create ,翻译功能可用

图32

33、编辑个人信息,设置本地为英语美国,如图33
编辑个人信息,设置本地为英语美国

图33

34、当本地设置为英语美国时,再次打开 http://backend.cmcp-api.localhost/page/create ,翻译功能可用,如图34
当本地设置为英语美国时,再次打开 http://backend.cmcp-api.localhost/page/create ,翻译功能可用

图34

35、开始实现 RESTful Web 服务,参考网址:https://www.shuijingwanwq.com/2016/11/28/1457/ ,如图35
开始实现 RESTful Web 服务,参考网址:https://www.shuijingwanwq.com/2016/11/28/1457/

图35

36、打开网址:http://backend.cmcp-api.localhost/article/create ,创建文章,如图36
打开网址:http://backend.cmcp-api.localhost/article/create ,创建文章

图36

37、在 Postman 中,GET http://frontend.cmcp-api.localhost/api/v1/articles ,此为自带的RESTful Web 服务,响应结果,如图37


{
    "items": [
        {
            "id": 1,
            "slug": "biao-ti20180104-0",
            "category_id": 1,
            "title": "标题20180104-0",
            "body": "

内容

",
            "published_at": 1515031309,
            "_links": {
                "self": {
                    "href": "http://frontend.cmcp-api.localhost/api/v1/articles/1"
                }
            }
        }
    ],
    "_links": {
        "self": {
            "href": "http://frontend.cmcp-api.localhost/api/v1/articles?page=1"
        }
    },
    "_meta": {
        "totalCount": 1,
        "pageCount": 1,
        "currentPage": 1,
        "perPage": 20
    }
}


在 Postman 中,GET http://frontend.cmcp-api.localhost/api/v1/articles ,此为自带的RESTful Web 服务,响应结果

图37

38、RESTful Web 服务,建议基于一个单独的接口应用来实现,而不是基于前台应用中的一个api模块来实现,这样可以更为方便地维护你的WEB应用程序,如图38
RESTful Web 服务,建议基于一个单独的接口应用来实现,而不是基于前台应用中的一个api模块来实现,这样可以更为方便地维护你的WEB应用程序

图38

39、新建目录:\api\rests,此目录将做为 RESTful Web 服务的操作方法类目录,如图39
新建目录:\api\rests,此目录将做为 RESTful Web 服务的操作方法类目录

图39

40、编辑控制器类 \api\controllers\PageController.php ,控制器类扩展自 [[yii\rest\ActiveController]]。 通过指定 [[yii\rest\ActiveController::modelClass|modelClass]] 作为 api\models\Page, 控制器就能知道使用哪个模型去获取和处理数据。如图40


namespace api\controllers;

use yii\rest\ActiveController;

class PageController extends ActiveController
{
    public $modelClass = 'api\models\Page';
}


编辑控制器类 \api\controllers\PageController.php ,控制器类扩展自 [[yii\rest\ActiveController]]。 通过指定 [[yii\rest\ActiveController::modelClass|modelClass]] 作为 api\models\Page, 控制器就能知道使用哪个模型去获取和处理数据。

图40

41、配置URL规则,修改有关在应用程序配置的urlManager组件的配置,编辑:\api\config\_urlManager.php,如图41


return [
    'class' => yii\web\UrlManager::class,
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
        [
            'class' => 'yii\rest\UrlRule',
            'controller' => ['page'],
        ],
    ],
];


配置URL规则,修改有关在应用程序配置的urlManager组件的配置,编辑:\api\config\_urlManager.php

图41

42、在 Postman 中,GET http://www.cmcp-api.localhost/pages ,403响应,如图42


{
    "name": "Forbidden",
    "message": "Login Required",
    "code": 0,
    "status": 403,
    "type": "yii\\web\\ForbiddenHttpException"
}


在 Postman 中,GET http://www.cmcp-api.localhost/pages ,403响应

图42

43、编辑 \api\config\web.php,注释附加的行为globalAccess,有待后期调整(验证、授权),如图43


    /*
    'as globalAccess' => [
        'class' => common\behaviors\GlobalAccessBehavior::class,
        'rules' => [
            [
                'controllers' => ['sign-in'],
                'allow' => true,
                'roles' => ['?'],
                'actions' => ['login']
            ],
            [
                'controllers' => ['sign-in'],
                'allow' => true,
                'roles' => ['@'],
                'actions' => ['logout']
            ],
            [
                'controllers' => ['site'],
                'allow' => true,
                'roles' => ['?', '@'],
                'actions' => ['error']
            ],
            [
                'controllers' => ['debug/default'],
                'allow' => true,
                'roles' => ['?'],
            ],
            [
                'controllers' => ['user'],
                'allow' => true,
                'roles' => ['administrator'],
            ],
            [
                'controllers' => ['user'],
                'allow' => false,
            ],
            [
                'allow' => true,
                'roles' => ['manager'],
            ]
        ]
    ]
    */


编辑 \api\config\web.php,注释附加的行为globalAccess,有待后期调整(验证、授权)

图43

44、在 Postman 中,GET http://www.cmcp-api.localhost/pages ,200响应,如图44


[
    {
        "id": 1,
        "slug": "about",
        "title": "About",
        "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "view": null,
        "status": 1,
        "created_at": 1514860785,
        "updated_at": 1514860785
    }
]


在 Postman 中,GET http://www.cmcp-api.localhost/pages ,200响应

图44

45、调用API服务后返回数据采用统一格式,返回的HTTP状态码为20x,代表调用成功;返回4xx或5xx的HTTP状态码代表调用失败。调整200响应的返回数据格式,与403响应一致,至少包含:”message”,”code”,新建语言包文件:\api\messages\zh\app.php(响应成功)、\api\messages\zh\error.php(响应失败),如图45


return [
    10000 => 'success',
    10001 => '获取页面列表成功',
];


调用API服务后返回数据采用统一格式,返回的HTTP状态码为20x,代表调用成功;返回4xx或5xx的HTTP状态码代表调用失败。调整200响应的返回数据格式,与403响应一致,至少包含:"message","code",新建语言包文件:\api\messages\zh\app.php(响应成功)、\api\messages\zh\error.php(响应失败)

图45

46、版本化的实现,参考网址:https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/rest-versioning.md ,编辑 \api\controllers\PageController.php,删除 modelClass,如图46
<pre class="wp-block-syntaxhighlighter-code">

<?php

namespace api\controllers;

use yii\rest\ActiveController;

class PageController extends ActiveController
{
}


</pre>
版本化的实现,参考网址:https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/rest-versioning.md ,编辑 \api\controllers\PageController.php,删除 modelClass

图46

47、把每个主要版本的 API 实现在一个单独的模块 ID 的主版本号,基于 Gii 生成模块 v1,打开网址:http://frontend.cmcp-api.localhost/gii/module ,如图47
把每个主要版本的 API 实现在一个单独的模块 ID 的主版本号,基于 Gii 生成模块 v1,打开网址:http://frontend.cmcp-api.localhost/gii/module

图47

48、新建 \api\modules\v1\models\Page.php,继承至 \api\models\Page.php,如图48 注:\api\modules\v1\models\Page(仅用于 v1 模块) > \api\models\Page(仅用于 api 应用) > \common\logics\Page.php(可用于 api、frontend 等多个应用) > \common\models\Page.php(仅限于 Gii 生成) > \yii\db\ActiveRecord
<pre class="wp-block-syntaxhighlighter-code">

<?php

namespace api\modules\v1\models;

class Page extends \api\models\Page
{

}


</pre>
新建 \api\modules\v1\models\Page.php,继承至 \api\models\Page.php

图48

49、\api\modules\v1\controllers\DefaultController.php 重命名为 \api\modules\v1\controllers\PageController.php,编辑代码,如图49 注:\api\modules\v1\controllers\PageController.php(仅用于 v1 模块) > \api\controllers\PageController.php(仅用于 api 应用) > \yii\rest\ActiveController
<pre class="wp-block-syntaxhighlighter-code">

<?php

namespace api\modules\v1\controllers;

/**
 * Page controller for the `v1` module
 */
class PageController extends \api\controllers\PageController
{
    public $modelClass = 'api\modules\v1\models\Page';
}


</pre>
\api\modules\v1\controllers\DefaultController.php 重命名为 \api\modules\v1\controllers\PageController.php,编辑代码

图49

50、要在应用中使用模块,只需要将模块加入到应用主体配置的[[yii\base\Application::modules|modules]]属性的列表中, 如下代码的应用主体配置 使用 v1 模块,编辑 \api\config\web.php,如图50


    'modules' => [
        'v1' => [
            'class' => api\modules\v1\Module::class,
        ],
        'i18n' => [
            'class' => api\modules\i18n\Module::class,
            'defaultRoute' => 'i18n-message/index'
        ]
    ],


要在应用中使用模块,只需要将模块加入到应用主体配置的[[yii\base\Application::modules|modules]]属性的列表中, 如下代码的应用主体配置 使用 v1 模块,编辑 \api\config\web.php

图50

51、配置URL规则,修改有关在应用程序配置的urlManager组件的配置,以支持 v1 模块,编辑:\api\config\_urlManager.php,如图51 注:通过配置 only 选项来明确列出哪些行为支持,v1/page 仅支持:’index’, ‘update’, ‘delete’, ‘options’
<pre class="wp-block-syntaxhighlighter-code">

<?php return [ 'class' => yii\web\UrlManager::class,
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        [
            'class' => 'yii\rest\UrlRule',
            'controller' => ['v1/page'],
            'only' => ['index', 'update', 'delete', 'options'],
        ],
    ],
];


</pre>
配置URL规则,修改有关在应用程序配置的urlManager组件的配置,以支持 v1 模块,编辑:\api\config\_urlManager.php

图51

52、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,如图52


[
    {
        "id": 1,
        "slug": "about",
        "title": "About",
        "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "view": null,
        "status": 1,
        "created_at": 1514860785,
        "updated_at": 1514860785
    }
]


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应

图52

53、测试 only 选项,在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,405响应(不被允许的方法。因为 ‘view’ 行为不被支持),测试通过,如图53
测试 only 选项,在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,405响应(不被允许的方法。因为 'view' 行为不被支持),测试通过

图53

54、配置URL规则,修改有关在应用程序配置的urlManager组件的配置,以支持 v1 模块,编辑:\api\config\_urlManager.php,如图54 注:取消配置 only 选项,以后续支持所有行为
<pre class="wp-block-syntaxhighlighter-code">

<?php return [ 'class' => yii\web\UrlManager::class,
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        [
            'class' => 'yii\rest\UrlRule',
            'controller' => ['v1/page'],
        ],
    ],
];


</pre>
配置URL规则,修改有关在应用程序配置的urlManager组件的配置,以支持 v1 模块,编辑:\api\config\_urlManager.php

图54

55、在 Postman 中,GET http://www.cmcp-api.localhost/v1 ,404响应,格式为HMTL,如图55
<pre class="wp-block-syntaxhighlighter-code">

<!DOCTYPE html>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
        <meta name="csrf-param" content="_csrf">
        <meta name="csrf-token" content="MtUm8pVxEHfmqhYMruxdUyScsktaMyFDc350jW_XR7dzmGqaoDRyT7bPc13M2W0AVNuGISJSbQUYOFn9LKNzgQ==">
        <title>Not Found (#404)</title>
        <link href="/assets/95b60493/themes/smoothness/jquery-ui.css?v=1514958071" rel="stylesheet">
        <link href="/assets/7635f0fe/css/bootstrap.css?v=1512021376" rel="stylesheet">
        <link href="/assets/1ee3df8/css/font-awesome.min.css?v=1512021376" rel="stylesheet">
        <link href="/assets/541f775b/css/AdminLTE.min.css?v=1512021373" rel="stylesheet">
        <link href="/assets/541f775b/css/skins/_all-skins.min.css?v=1512021373" rel="stylesheet">
        <link href="/css/style.css?v=1512021342" rel="stylesheet">

    </head>
    <body class=" skin-blue ">
    </body>
</html>

</pre>
在 Postman 中,GET http://www.cmcp-api.localhost/v1 ,404响应,格式为HMTL

图55

56、对于404响应格式为HTML的解决,编辑 \api\config\web.php,设置默认的响应格式为JSON,如图56


        'response' => [
            'format' => yii\web\Response::FORMAT_JSON,
        ],


对于404响应格式为HTML的解决,编辑 \api\config\web.php,设置默认的响应格式为JSON

图56

57、在 Postman 中,GET http://www.cmcp-api.localhost/v1 ,404响应,格式为JSON,如图57


{
    "name": "Not Found",
    "message": "Page not found.",
    "code": 0,
    "status": 404,
    "type": "yii\\web\\NotFoundHttpException"
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1 ,404响应,格式为JSON

图57

58、数据序列化的实现,在响应主体内包含分页信息来简化客户端的开发工作,编辑 \api\controllers\PageController.php,如图58
<pre class="wp-block-syntaxhighlighter-code">

<?php namespace api\controllers; use yii\rest\ActiveController; class PageController extends ActiveController { public $serializer = [ 'class' => 'yii\rest\Serializer',
        'collectionEnvelope' => 'items',
    ];
}


</pre>
数据序列化的实现,在响应主体内包含分页信息来简化客户端的开发工作,编辑 \api\controllers\PageController.php

图58

59、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,在响应主体内包含分页信息,如图59


{
    "items": [
        {
            "id": 1,
            "slug": "about",
            "title": "About",
            "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "view": null,
            "status": 1,
            "created_at": 1514860785,
            "updated_at": 1514860785
        }
    ],
    "_links": {
        "self": {
            "href": "http://www.cmcp-api.localhost/v1/pages?page=1"
        }
    },
    "_meta": {
        "totalCount": 1,
        "pageCount": 1,
        "currentPage": 1,
        "perPage": 20
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,在响应主体内包含分页信息

图59

60、RESTful APIs 通常是无状态的,因此,配置 user 应用组件,编辑 \api\config\web.php,如图60 注:配置user 应用组件: 设置 [[yii\web\User::enableSession|enableSession]] 属性为 false. 设置 [[yii\web\User::loginUrl|loginUrl]] 属性为null 显示一个HTTP 403 错误而不是跳转到登录界面.


        'user' => [
            'class' => yii\web\User::class,
            'identityClass' => common\models\User::class,
            'enableSession' => false,
            'loginUrl' => null,
            'enableAutoLogin' => false,
            'as afterLogin' => common\behaviors\LoginTimestampBehavior::class
        ],


RESTful APIs 通常是无状态的,因此,配置 user 应用组件,编辑 \api\config\web.php

图60

61、复制目录 \vendor\yiisoft\yii2\rest 下的 Action.php、IndexAction.php、ViewAction.php、CreateAction.php、UpdateAction.php、DeleteAction.php、Serializer.php 至目录 \api\rests\page,如图61
复制目录 \vendor\yiisoft\yii2\rest 下的 Action.php、IndexAction.php、ViewAction.php、CreateAction.php、UpdateAction.php、DeleteAction.php、Serializer.php 至目录 \api\rests\page

图61

62、如果为多个单词组合的目录,建议目录使用小写+下划线,参考网址:https://github.com/hfcorriez/fig-standards/blob/master/accepted/zh_CN/PSR-0.md ,编辑 \api\controllers\PageController.php,如图62
<pre class="wp-block-syntaxhighlighter-code">

<?php namespace api\controllers; use yii\rest\ActiveController; class PageController extends ActiveController { public $serializer = [ 'class' => 'api\rests\page\Serializer',
        'collectionEnvelope' => 'items',
    ];

    /**
     * @inheritdoc
     */
    public function actions()
    {
        return [
            'index' => [
                'class' => 'api\rests\page\IndexAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
            ],
            'view' => [
                'class' => 'api\rests\page\ViewAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
            ],
            'create' => [
                'class' => 'api\rests\page\CreateAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
                'scenario' => $this->createScenario,
            ],
            'update' => [
                'class' => 'api\rests\page\UpdateAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
                'scenario' => $this->updateScenario,
            ],
            'delete' => [
                'class' => 'api\rests\page\DeleteAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
            ],
            'options' => [
                'class' => 'yii\rest\OptionsAction',
            ],
        ];
    }
}


</pre>
注:如果仅支持较少的行为,可以选择下面的方案,例


    public function actions()
    {
        $actions = parent::actions();
        
        $actions['view']['class'] = 'api\rests\page\ViewAction';

        return $actions;
    }


如果为多个单词组合的目录,建议目录使用小写+下划线,参考网址:https://github.com/hfcorriez/fig-standards/blob/master/accepted/zh_CN/PSR-0.md ,编辑 \api\controllers\PageController.php

图62

63、编辑 \api\rests\page\IndexAction.php,调整命名空间、继承关系、查询条件等,如图63
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\data\ActiveDataProvider;

/**
 * IndexAction implements the API endpoint for listing multiple models.
 *
 * For more details and usage information on IndexAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class IndexAction extends \yii\rest\IndexAction
{
    const STATUS_INACTIVE = 0; //状态:不活跃
    const STATUS_ACTIVE = 1; //状态:活跃

    /**
     * Prepares the data provider that should return the requested collection of the models.
     * @return ActiveDataProvider
     */
    protected function prepareDataProvider()
    {
        $requestParams = Yii::$app->getRequest()->getBodyParams();
        if (empty($requestParams)) {
            $requestParams = Yii::$app->getRequest()->getQueryParams();
        }

        $filter = null;
        if ($this->dataFilter !== null) {
            $this->dataFilter = Yii::createObject($this->dataFilter);
            if ($this->dataFilter->load($requestParams)) {
                $filter = $this->dataFilter->build();
                if ($filter === false) {
                    return $this->dataFilter;
                }
            }
        }

        if ($this->prepareDataProvider !== null) {
            return call_user_func($this->prepareDataProvider, $this, $filter);
        }

        /* @var $modelClass \yii\db\BaseActiveRecord */
        $modelClass = $this->modelClass;

        $query = $modelClass::find()->where(['status' => self::STATUS_ACTIVE]);
        if (!empty($filter)) {
            $query->andWhere($filter);
        }

        return Yii::createObject([
            'class' => ActiveDataProvider::className(),
            'query' => $query,
            'pagination' => [
                'params' => $requestParams,
            ],
            'sort' => [
                'params' => $requestParams,
            ],
        ]);
    }
}


</pre>
编辑 \api\rests\page\IndexAction.php,调整命名空间、继承关系、查询条件等

图63

64、编辑 \api\rests\page\Serializer.php,调整命名空间、继承关系、响应结构(响应成功:”code”: 10000,”message”,”data”;响应失败:”code”: 不等于10000的其他数字,”message”)等,如图64
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\data\DataProviderInterface;

/**
 * Serializer converts resource objects and collections into array representation.
 *
 * Serializer is mainly used by REST controllers to convert different objects into array representation
 * so that they can be further turned into different formats, such as JSON, XML, by response formatters.
 *
 * The default implementation handles resources as [[Model]] objects and collections as objects
 * implementing [[DataProviderInterface]]. You may override [[serialize()]] to handle more types.
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class Serializer extends \yii\rest\Serializer
{
    /**
     * Serializes a data provider.
     * @param DataProviderInterface $dataProvider
     * @return array the array representation of the data provider.
     */
    protected function serializeDataProvider($dataProvider)
    {
        if ($this->preserveKeys) {
            $models = $dataProvider->getModels();
        } else {
            $models = array_values($dataProvider->getModels());
        }
        $models = $this->serializeModels($models);

        if (($pagination = $dataProvider->getPagination()) !== false) {
            $this->addPaginationHeaders($pagination);
        }

        if ($this->request->getIsHead()) {
            return null;
        } elseif ($this->collectionEnvelope === null) {
            return $models;
        }

        $result = [
            $this->collectionEnvelope => $models,
        ];

        if (empty($result['items'])) {
            return ['code' => 20001, 'message' => Yii::t('error', '20001')];
        }

        if ($pagination !== false) {
            return ['code' => 10000, 'message' => Yii::t('app', '10001'), 'data' => array_merge($result, $this->serializePagination($pagination))];
        }

        return ['code' => 10000, 'message' => Yii::t('app', '10001'), 'data' => $result];
    }
}


</pre>
编辑 \api\rests\page\Serializer.php,调整命名空间、继承关系、响应结构(响应成功:"code": 10000,"message","data";响应失败:"code": 不等于10000的其他数字,"message")等

图64

65、编辑 \api\config\base.php,配置接口应用的 i18n 应用组件 ,如图65


        'i18n' => [
            'translations' => [
                'model/*'=> [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'forceTranslation' => true,
                    'basePath'=>'@common/messages',
                    'fileMap'=>[
                    ],
                ],
                'app'=> [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'forceTranslation' => true,
                    'basePath'=>'@api/messages',
                    'fileMap'=>[
                    ],
                ],
                '*'=> [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'forceTranslation' => true,
                    'basePath'=>'@api/messages',
                    'fileMap'=>[
                    ],
                ],
            ],
        ],


编辑 \api\config\base.php,配置接口应用的 i18n 应用组件

图65

66、新建语言包文件:\api\messages\zh\error.php(简体中文、响应失败),如图66


return [
    20000 => 'error',
    20001 => '页面列表为空',
];


新建语言包文件:\api\messages\zh\error.php(简体中文、响应失败)

图66

67、新建语言包文件:\api\messages\en\app.php(英语美国、响应成功),如图67


return [
    10000 => 'success',
    10001 => 'Get page list is successful',
];


新建语言包文件:\api\messages\en\app.php(英语美国、响应成功)

图67

68、新建语言包文件:\api\messages\en\error.php(英语美国、响应失败),如图68


return [
    20000 => 'error',
    20001 => 'Page list is empty',
];


新建语言包文件:\api\messages\en\error.php(英语美国、响应失败)

图68

69、打开网址:http://backend.cmcp-api.localhost/page/update?id=1 ,编辑文章,活跃复选框取消选中,如图69
打开网址:http://backend.cmcp-api.localhost/page/update?id=1 ,编辑文章,活跃复选框取消选中

图69

70、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表为空,如图70 注: Accept application/json; version=0.0


{
    "code": 20001,
    "message": "Page list is empty"
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表为空

图70

71、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表为空,如图71 注: Accept application/json; version=0.0 Accept-Language zh-CN


{
    "code": 20001,
    "message": "页面列表为空"
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表为空

图71

72、打开网址:http://backend.cmcp-api.localhost/page/update?id=1 ,编辑文章,活跃复选框勾选,如图72
打开网址:http://backend.cmcp-api.localhost/page/update?id=1 ,编辑文章,活跃复选框勾选

图72

73、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表不为空,如图73 注: Accept application/json; version=0.0 Accept-Language en-US


{
    "code": 10000,
    "message": "Get page list is successful",
    "data": {
        "items": [
            {
                "id": 1,
                "slug": "about",
                "title": "About",
                "body": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

",
                "view": "",
                "status": 1,
                "created_at": 1514860785,
                "updated_at": 1515482758
            }
        ],
        "_links": {
            "self": {
                "href": "http://www.cmcp-api.localhost/v1/pages?page=1"
            }
        },
        "_meta": {
            "totalCount": 1,
            "pageCount": 1,
            "currentPage": 1,
            "perPage": 20
        }
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表不为空

图73

74、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表不为空,如图74 注: Accept application/json; version=0.0 Accept-Language zh-CN


{
    "code": 10000,
    "message": "获取页面列表成功",
    "data": {
        "items": [
            {
                "id": 1,
                "slug": "about",
                "title": "About",
                "body": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

",
                "view": "",
                "status": 1,
                "created_at": 1514860785,
                "updated_at": 1515482758
            }
        ],
        "_links": {
            "self": {
                "href": "http://www.cmcp-api.localhost/v1/pages?page=1"
            }
        },
        "_meta": {
            "totalCount": 1,
            "pageCount": 1,
            "currentPage": 1,
            "perPage": 20
        }
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages ,200响应,状态为活跃的页面列表不为空

图74

75、GET /pages/1: 返回页面 1 的详细信息,编辑 \api\rests\page\Action.php,调整命名空间、继承关系、响应结构等,如图75
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\db\ActiveRecordInterface;
use yii\web\NotFoundHttpException;

/**
 * Action is the base class for action classes that implement RESTful API.
 *
 * For more details and usage information on Action, see the [guide article on rest controllers](guide:rest-controllers).
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class Action extends \yii\rest\Action
{
    /**
     * Returns the data model based on the primary key given.
     * If the data model is not found, a 404 HTTP exception will be raised.
     * @param string $id the ID of the model to be loaded. If the model has a composite primary key,
     * the ID must be a string of the primary key values separated by commas.
     * The order of the primary key values should follow that returned by the `primaryKey()` method
     * of the model.
     * @return ActiveRecordInterface the model found
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function findModel($id)
    {
        if ($this->findModel !== null) {
            return call_user_func($this->findModel, $id, $this);
        }

        /* @var $modelClass ActiveRecordInterface */
        $modelClass = $this->modelClass;
        $keys = $modelClass::primaryKey();
        if (count($keys) > 1) {
            $values = explode(',', $id);
            if (count($keys) === count($values)) {
                $model = $modelClass::findOne(array_combine($keys, $values));
            }
        } elseif ($id !== null) {
            $model = $modelClass::findOne($id);
        }

        if (isset($model)) {
            return $model;
        }

        throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20002'), ['id' => $id])), 20002);
    }
}


</pre>
GET /pages/1: 返回页面 1 的详细信息,编辑 \api\rests\page\Action.php,调整命名空间、继承关系、响应结构等

图75

76、编辑 \api\rests\page\ViewAction.php,调整命名空间、继承关系、响应结构等,如图76
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;

/**
 * ViewAction implements the API endpoint for returning the detailed information about a model.
 *
 * For more details and usage information on ViewAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class ViewAction extends Action
{
    const STATUS_INACTIVE = 0; //状态:不活跃
    const STATUS_ACTIVE = 1; //状态:活跃

    /**
     * Displays a model.
     * @param string $id the primary key of the model.
     * @return \yii\db\ActiveRecordInterface the model being displayed
     */
    public function run($id)
    {
        $model = $this->findModel($id);
        if ($this->checkAccess) {
            call_user_func($this->checkAccess, $this->id, $model);
        }

        /* 判断状态,如果为不活跃,则返回失败 */
        if ($model->status === self::STATUS_INACTIVE) {
            return ['code' => 20003, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20003'), ['id' => $id]))];
        }

        return ['code' => 10000, 'message' => Yii::t('app', '10002'), 'data' => $model];
    }
}


</pre>
编辑 \api\rests\page\ViewAction.php,调整命名空间、继承关系、响应结构等

图76

77、编辑语言包文件:\api\messages\zh\app.php(简体中文、响应成功)、\api\messages\zh\error.php(简体中文、响应失败)、\api\messages\en\app.php(英语美国、响应成功)、\api\messages\en\error.php(英语美国、响应失败),如图77 \api\messages\zh\app.php


return [
    10000 => 'success',
    10001 => '获取页面列表成功',
    10002 => '获取页面详情成功',
];


\api\messages\zh\error.php


return [
    20000 => 'error',
    20001 => '页面列表为空',
    20002 => '页面ID:{id},不存在',
    20003 => '页面ID:{id},的状态不活跃',
];


\api\messages\en\app.php


return [
    10000 => 'success',
    10001 => 'Get page list is successful',
    10002 => 'Get page details succeeded',
];


\api\messages\en\error.php


return [
    20000 => 'error',
    20001 => 'Page list is empty',
    20002 => 'Page ID: {id}, does not exist',
    20003 => 'Page ID: {id}, the status is not active',
];


编辑语言包文件:\api\messages\zh\app.php(简体中文、响应成功)、\api\messages\zh\error.php(简体中文、响应失败)、\api\messages\en\app.php(英语美国、响应成功)、\api\messages\en\error.php(英语美国、响应失败)

图77

78、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,其状态为活跃,如图78 注: Accept application/json; version=0.0 Accept-Language zh-CN


{
    "code": 10000,
    "message": "获取页面详情成功",
    "data": {
        "id": 2,
        "slug": "contact",
        "title": "Contact",
        "body": "

Contact

",
        "view": "",
        "status": 1,
        "created_at": 1515488912,
        "updated_at": 1515488912
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,其状态为活跃

图78

79、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,其状态为活跃,如图79 注: Accept application/json; version=0.0 Accept-Language en-US


{
    "code": 10000,
    "message": "Get page details succeeded",
    "data": {
        "id": 2,
        "slug": "contact",
        "title": "Contact",
        "body": "

Contact

",
        "view": "",
        "status": 1,
        "created_at": 1515488912,
        "updated_at": 1515488912
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,其状态为活跃

图79

80、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/2 ,200响应,其状态为不活跃,如图80 注: Accept application/json; version=0.0 Accept-Language en-US


{
    "code": 20003,
    "message": "Page ID: 2, the status is not active"
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/2 ,200响应,其状态为不活跃

图80

81、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/3 ,404响应,页面不存在,如图81 注: Accept application/json; version=0.0 Accept-Language zh-CN


{
    "name": "Not Found",
    "message": "页面ID:3,不存在",
    "code": 20002,
    "status": 404,
    "type": "yii\\web\\NotFoundHttpException"
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/3 ,404响应,页面不存在

图81

82、实现[[yii\web\Linkable]] 接口来支持HATEOAS,返回与本资源对象的相关链接,编辑资源类 \api\models\Page.php,如图82
<pre class="wp-block-syntaxhighlighter-code">

<?php namespace api\models; use yii\helpers\Url; use yii\web\Linkable; use yii\web\Link; class Page extends \common\logics\Page implements Linkable { /** * Returns a list of links. * * @return array the links */ public function getLinks() { return [ Link::REL_SELF => Url::to(['page/view', 'id' => $this->id], true),
            'index' => Url::to(['page/index'], true),
            'view' => Url::to(['page/view', 'id' => $this->id], true),
            'create' => Url::to(['page/index'], true),
            'update' => Url::to(['page/view', 'id' => $this->id], true),
            'delete' => Url::to(['page/view', 'id' => $this->id], true),
            'options' => Url::to(['page/index'], true),

        ];
    }
}


</pre>
实现[[yii\web\Linkable]] 接口来支持HATEOAS,返回与本资源对象的相关链接,编辑资源类 \api\models\Page.php

图82

83、在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,支持HATEOAS,如图83 注: Accept application/json; version=0.0 Accept-Language zh-CN Accept-Encoding gzip, deflate, br


{
    "code": 10000,
    "message": "获取页面详情成功",
    "data": {
        "id": 1,
        "slug": "about",
        "title": "About",
        "body": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

",
        "view": "",
        "status": 1,
        "created_at": 1514860785,
        "updated_at": 1515548927,
        "_links": {
            "self": {
                "href": "http://www.cmcp-api.localhost/v1/pages/1"
            },
            "index": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "view": {
                "href": "http://www.cmcp-api.localhost/v1/pages/1"
            },
            "create": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "update": {
                "href": "http://www.cmcp-api.localhost/v1/pages/1"
            },
            "delete": {
                "href": "http://www.cmcp-api.localhost/v1/pages/1"
            },
            "options": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            }
        }
    }
}


在 Postman 中,GET http://www.cmcp-api.localhost/v1/pages/1 ,200响应,支持HATEOAS

图83

84、POST /pages: 创建一个新页面,编辑 \api\rests\page\CreateAction.php,如图84
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\base\Model;
use yii\helpers\Url;
use yii\web\ServerErrorHttpException;

/**
 * CreateAction implements the API endpoint for creating a new model from the given data.
 *
 * 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);
        }

        /* @var $model \yii\db\ActiveRecord */
        $model = new $this->modelClass([
            'scenario' => $this->scenario,
        ]);

        $model->load(Yii::$app->getRequest()->getBodyParams(), '');
        if ($model->save()) {
            $response = Yii::$app->getResponse();
            $response->setStatusCode(201);
            $id = implode(',', array_values($model->getPrimaryKey(true)));
            $response->getHeaders()->set('Location', Url::toRoute([$this->viewAction, 'id' => $id], true));
        } elseif ($model->hasErrors()) {
            $response = Yii::$app->getResponse();
            $response->setStatusCode(422, 'Data Validation Failed.');
            foreach ($model->getFirstErrors() as $message) {
                $firstErrors = $message;
            }
            return ['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.');
        }

        return ['code' => 10000, 'message' => Yii::t('app', '10003'), 'data' => $model];
    }
}


</pre>
POST /pages: 创建一个新页面,编辑 \api\rests\page\CreateAction.php

图84

85、在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,201响应,如图85 注: Accept application/json; version=0.0 Accept-Language zh-CN Accept-Encoding gzip, deflate, br Content-Type application/x-www-form-urlencoded


{
    "code": 10000,
    "message": "创建页面成功",
    "data": {
        "slug": "slug-20180110-4",
        "title": "title-20180110-4",
        "body": "body-20180110-4",
        "view": "view-20180110-4",
        "status": "0",
        "created_at": 1515566824,
        "updated_at": 1515566824,
        "id": 7,
        "_links": {
            "self": {
                "href": "http://www.cmcp-api.localhost/v1/pages/7"
            },
            "index": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "view": {
                "href": "http://www.cmcp-api.localhost/v1/pages/7"
            },
            "create": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "update": {
                "href": "http://www.cmcp-api.localhost/v1/pages/7"
            },
            "delete": {
                "href": "http://www.cmcp-api.localhost/v1/pages/7"
            },
            "options": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            }
        }
    }
}


在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,201响应

图85

86、在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,参数保持原样,422响应,如图86 注: Accept application/json; version=0.0 Accept-Language zh-CN Accept-Encoding gzip, deflate, br Content-Type application/x-www-form-urlencoded


{
    "code": 20004,
    "message": "数据验证失败:Slug的值\"slug-20180110-4\"已经被占用了。"
}


在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,参数保持原样,422响应

图86

87、在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,422响应(数据验证失败 (例如,响应一个 POST 请求)。 请检查响应体内详细的错误消息。),如图87 注: Accept application/json; version=0.0 Accept-Language zh-CN Accept-Encoding gzip, deflate, br Content-Type application/x-www-form-urlencoded Body 缺少 title 参数


{
    "code": 20004,
    "message": "数据验证失败:Title不能为空。"
}


在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,422响应(数据验证失败 (例如,响应一个 POST 请求)。 请检查响应体内详细的错误消息。)

图87

88、在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,422响应,如图88 注: Accept application/json; version=0.0 Accept-Language en-US Accept-Encoding gzip, deflate, br Content-Type application/x-www-form-urlencoded Body 缺少 title 参数


{
    "code": 20004,
    "message": "Data validation failed: Title cannot be blank."
}


在 Postman 中,POST http://www.cmcp-api.localhost/v1/pages ,422响应

图88

89、PUT /pages/4: 更新一个页面,编辑 \api\rests\page\UpdateAction.php,如图89
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\base\Model;
use yii\db\ActiveRecord;
use yii\web\ServerErrorHttpException;

/**
 * UpdateAction implements the API endpoint for updating a model.
 *
 * For more details and usage information on UpdateAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class UpdateAction extends Action
{
    /**
     * @var string the scenario to be assigned to the model before it is validated and updated.
     */
    public $scenario = Model::SCENARIO_DEFAULT;


    /**
     * Updates an existing model.
     * @param string $id the primary key of the model.
     * @return \yii\db\ActiveRecordInterface the model being updated
     * @throws ServerErrorHttpException if there is any error when updating the model
     */
    public function run($id)
    {
        /* @var $model ActiveRecord */
        $model = $this->findModel($id);

        if ($this->checkAccess) {
            call_user_func($this->checkAccess, $this->id, $model);
        }

        $model->scenario = $this->scenario;
        $model->load(Yii::$app->getRequest()->getBodyParams(), '');
        if ($model->save() === false) {
            if ($model->hasErrors()) {
                $response = Yii::$app->getResponse();
                $response->setStatusCode(422, 'Data Validation Failed.');
                foreach ($model->getFirstErrors() as $message) {
                    $firstErrors = $message;
                }
                return ['code' => 20004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20004'), ['firstErrors' => $firstErrors]))];
            } elseif (!$model->hasErrors()) {
                throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
            }
        }

        return ['code' => 10000, 'message' => Yii::t('app', '10004'), 'data' => $model];
    }
}


</pre>
PUT /pages/4: 更新一个页面,编辑 \api\rests\page\UpdateAction.php

图89

90、在 Postman 中,PUT http://www.cmcp-api.localhost/v1/pages/4 ,200响应,如图90


{
    "code": 10000,
    "message": "更新页面成功",
    "data": {
        "id": 4,
        "slug": "slug-20180110-44",
        "title": "title-20180110-44",
        "body": "body-20180110-44",
        "view": "view-20180110-44",
        "status": "1",
        "created_at": 1515554512,
        "updated_at": 1515569633,
        "_links": {
            "self": {
                "href": "http://www.cmcp-api.localhost/v1/pages/4"
            },
            "index": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "view": {
                "href": "http://www.cmcp-api.localhost/v1/pages/4"
            },
            "create": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            },
            "update": {
                "href": "http://www.cmcp-api.localhost/v1/pages/4"
            },
            "delete": {
                "href": "http://www.cmcp-api.localhost/v1/pages/4"
            },
            "options": {
                "href": "http://www.cmcp-api.localhost/v1/pages"
            }
        }
    }
}


在 Postman 中,PUT http://www.cmcp-api.localhost/v1/pages/4 ,200响应

图90

91、在 Postman 中,PUT http://www.cmcp-api.localhost/v1/pages/4 ,422响应,如图91 注: Accept application/json; version=0.0 Accept-Language en-US Accept-Encoding gzip, deflate, br Content-Type application/x-www-form-urlencoded Body slug 的值已经被另一页面占用


{
    "code": 20004,
    "message": "Data validation failed: Slug \"slug-20180110-5\" has already been taken."
}


在 Postman 中,PUT http://www.cmcp-api.localhost/v1/pages/4 ,422响应

图91

92、DELETE /pages/4: 删除页面4,编辑 \api\rests\page\DeleteAction.php,如图92
<pre class="wp-block-syntaxhighlighter-code">

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace api\rests\page;

use Yii;
use yii\web\ServerErrorHttpException;

/**
 * DeleteAction implements the API endpoint for deleting a model.
 *
 * For more details and usage information on DeleteAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class DeleteAction extends Action
{
    /**
     * Deletes a model.
     * @param mixed $id id of the model to be deleted.
     * @throws ServerErrorHttpException on failure.
     */
    public function run($id)
    {
        $model = $this->findModel($id);

        if ($this->checkAccess) {
            call_user_func($this->checkAccess, $this->id, $model);
        }

        if ($model->delete() === false) {
            throw new ServerErrorHttpException('Failed to delete the object for unknown reason.');
        }

        return ['code' => 10000, 'message' => Yii::t('app', '10005')];
    }
}


</pre>
DELETE /pages/4: 删除页面4,编辑 \api\rests\page\DeleteAction.php

图92

93、在 Postman 中,DELETE http://www.cmcp-api.localhost/v1/pages/7 ,200响应,如图93 注: Accept application/json; version=0.0 Accept-Language zh-CN Accept-Encoding gzip, deflate, br


{
    "code": 10000,
    "message": "删除页面成功"
}


在 Postman 中,DELETE http://www.cmcp-api.localhost/v1/pages/7 ,200响应

图93

94、展示一下语言包文件的最后内容,如图94 \api\messages\zh\app.php


return [
    10000 => 'success',
    10001 => '获取页面列表成功',
    10002 => '获取页面详情成功',
    10003 => '创建页面成功',
    10004 => '更新页面成功',
    10005 => '删除页面成功',
];


\api\messages\zh\error.php


return [
    20000 => 'error',
    20001 => '页面列表为空',
    20002 => '页面ID:{id},不存在',
    20003 => '页面ID:{id},的状态不活跃',
    20004 => '数据验证失败:{firstErrors}',
];


\api\messages\en\app.php


return [
    10000 => 'success',
    10001 => 'Get page list is successful',
    10002 => 'Get page details succeeded',
    10003 => 'Create a page success',
    10004 => 'Update page success',
    10005 => 'Delete page success',
];


\api\messages\en\error.php


return [
    20000 => 'error',
    20001 => 'Page list is empty',
    20002 => 'Page ID: {id}, does not exist',
    20003 => 'Page ID: {id}, the status is not active',
    20004 => 'Data validation failed: {firstErrors}',
];


展示一下语言包文件的最后内容

图94

95、OPTIONS /pages: 显示关于末端 /pages 支持的动词,在 Postman 中,OPTIONS http://www.cmcp-api.localhost/v1/pages ,200响应,如图95
OPTIONS /pages: 显示关于末端 /pages 支持的动词,在 Postman 中,OPTIONS http://www.cmcp-api.localhost/v1/pages ,200响应

图95

96、OPTIONS /pages/1: 显示关于末端 /pages/1 支持的动词,在 Postman 中,OPTIONS http://www.cmcp-api.localhost/v1/pages/1 ,200响应,如图96
OPTIONS /pages/1: 显示关于末端 /pages/1 支持的动词,在 Postman 中,OPTIONS http://www.cmcp-api.localhost/v1/pages/1 ,200响应

图96

97、总结:现在支持的行为:index、view、create、update、delete、options,除 options 之外,基本上是继承之后,再次覆写实现具体的需求了的。  ]]>
https://www.shuijingwanwq.com/2018/01/10/2206/feed/ 1
在YII中采用了CActiveForm的checkBoxList生成的复选框组的提交数组写入数据库中转换为字条串的方案! https://www.shuijingwanwq.com/2014/02/21/192/ https://www.shuijingwanwq.com/2014/02/21/192/#respond Fri, 21 Feb 2014 03:56:04 +0000 http://www.shuijingwanwq.com/?p=192 Post Views: 69

视图代码:

视图代码截图 checkBoxList

视图代码截图 checkBoxList

视图界面:

视图界面 ajax验证

视图界面 ajax验证

提交之后的POST打印:

提交之后的POST打印

提交之后的POST打印

 

需求:question_type要插入数据库中,为字符串

解决方案1,直接重置$_POST[‘QuestionOrder’][‘question_type’]:

解决方案1,直接重置$_POST['QuestionOrder']['question_type']

解决方案1,直接重置$_POST[‘QuestionOrder’][‘question_type’]

重新打印出POST变量:

重新打印出POST变量

重新打印出POST变量

解决方案2:

 

解决方案2

解决方案2

结果便是两种方案均是可以在question_type    问题类型(1补货 2换货 3退货 4退款 5其他)字段中插入:|1|3|4|。

 

 

 

 

]]>
https://www.shuijingwanwq.com/2014/02/21/192/feed/ 0