在 Windwos 10 下 基于 Yii2 高级应用模板,实现 RESTful Web 服务的流程

1、请先参考上一篇博客:http://www.shuijingwanwq.com/2016/11/26/1436/

2、准备基于 shujujiexi 实现 RESTful Web 服务

3、基于 frontend 应用上的 Gii 生成模型,编辑\environments\dev\frontend\config\main-local.php,如图1

    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        'allowedIPs' => ['127.0.0.1', '::1'],
    ];

图1

4、在 Windows PowerShell 中执行 .\init,以覆盖\frontend\config\main-local.php,设置 Gii 允许访问的IP,如图2

图2

5、打开网址:http://www.kaiqiu_shujujiexi_api.dev/index.php?r=gii,可以访问 Gii 了,如图3

图3

6、编辑\frontend\config\main.php,以支持网址美化,如图4

        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
            ],
        ],

图4

7、打开网址:http://www.kaiqiu_shujujiexi_api.dev/gii,如图5

图5

8、基于数据库表kq_schedule建立相应模型,如图6

图6

9、点击Model Generator下的Start按钮,生成模型Schedule,命名空间为common\models,以便于后期其他应用皆可以使用此模型,此时无需支持国际化,如图7

图7

10、点击 Generate 按钮,生成模型文件\common\models\Schedule.php,如图8

图8

11、创建一个控制器\shujujiexi\controllers\ScheduleController.php,如图9

图9

 

<?php

namespace shujujiexi\controllers;

use yii\rest\ActiveController;

class ScheduleController extends ActiveController
{

    public $modelClass = 'common\models\Schedule';
}

12、配置URL规则,修改urlManager组件的配置,如图10

图10

 

        'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                [
                    'class' => 'yii\rest\UrlRule',
                    'controller' => 'schedule',
                ],
            ],
        ],

13、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules,正确响应,如图11

图11

14、为了在shujujiexi应用中实现自身的业务逻辑,建议新建\shujujiexi\models\Schedule.php,其继承至\common\models\Schedule,如图12

图12

15、编辑控制器\shujujiexi\controllers\ScheduleController.php,重新指定模型为shujujiexi\models\Schedule,如图13

图13

16、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules,正确响应,如图11

图11

17、在Postman中PUT:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules/1,正确响应,如图14

图14

18、配置 only 和 except 选项来明确列出哪些行为支持, 哪些行为禁用。例如,只让其支持GET列表,则可以修改urlManager组件的配置,如图15

图15

 

        'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                [
                    'class' => 'yii\rest\UrlRule',
                    'controller' => 'schedule',
                    'only' => ['index'],
                ],
            ],
        ],

19、在Postman中PUT:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules/1,404响应,如图16

图16

20、基于URL规则:’GET,HEAD users’ => ‘user/index’,,在Postman中HEAD:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules,空响应,可以不用理会,其他请求皆为404,如图17

图17

21、对于404响应格式为HTML的解决,编辑\shujujiexi\config\main.php,设置默认的响应格式为JSON,如图18

图18

 

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

22、再次执行第19项,404响应,其格式为JSON,如图19

图19

23、数据序列化的实现,在响应主体内包含分页信息来 简化客户端的开发工作,编辑\shujujiexi\controllers\ScheduleController.php,如图20

图20

 

    public $serializer = [
        'class' => 'yii\rest\Serializer',
        'collectionEnvelope' => 'items',
    ];

24、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules,正确响应,在响应主体内包含分页信息,如图21

图21

25、RESTful APIs 通常是无状态的,因此,配置user 应用组件,编辑\shujujiexi\config\main.php,如图22

图22

 

        'user' => [
            'identityClass' => 'common\models\User',
            'enableAutoLogin' => false,
            'identityCookie' => ['name' => '_identity-shujujiexi', 'httpOnly' => true],
            'enableSession' => false,
            'loginUrl' => null,
        ],

26、版本化的实现,新建目录\shujujiexi\modules,其结构如图23

图23

27、\shujujiexi\modules\v1\Module.php,其内容,如图24

图24

28、\shujujiexi\modules\v1\controllers\ScheduleController.php,其内容,如图25

图25

29、\shujujiexi\modules\v1\models\Schedule.php,其内容,如图26

图26

30、配置URL规则,修改urlManager组件的配置,如图27

图27

31、配置模块规则,如图28

图28

 

    'modules' => [
        'v1' => [
            'basePath' => '@app/modules/v1',
            'class' => 'shujujiexi\modules\v1\Module'
        ],
    ],

31、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/schedules,404响应,符合预期,如图29

图29

32、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/v1/schedules,正确响应,如图30

图30

33、响应数据的结构调整,默认为code、message、data字段

34、复制\vendor\yiisoft\yii2\rest\Serializer.php为\shujujiexi\rests\Serializer.php,其内容,继承至\yii\rest\Serializer,且只保留serializeDataProvider(),如图31

图31

 

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

use Yii;

/**
 * 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 Xue <qiang.xue@gmail.com>
 * @since 2.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;
        } else {
            $result = [
                $this->collectionEnvelope => $models,
            ];
            if ($pagination !== false) {
                return ['code' => '00000', 'message' => 'success', 'data' => array_merge($result, $this->serializePagination($pagination))];
                // return array_merge($result, $this->serializePagination($pagination));
            } else {
                return ['code' => '00000', 'message' => 'success', 'data' => $result];
                // return $result;
            }
        }
    }

}

35、编辑控制器\shujujiexi\controllers\ScheduleController.php,如图32

图32

36、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/v1/schedules,正确响应,如图33

图33

37、如何自由定义此请求的响应的实现流程,分析\vendor\yiisoft\yii2\rest\ActiveController.php可发现,Index操作默认实现类为yii\rest\IndexAction,如图34

图34

38、复制\vendor\yiisoft\yii2\rest\IndexAction.php至\shujujiexi\rests\schedule\IndexAction.php,如图35

图35

39、编辑控制器\shujujiexi\controllers\ScheduleController.php,如图36

图36

 

    public function actions()
    {
        $actions = parent::actions();
        
        $actions['index']['class'] = 'shujujiexi\rests\schedule\IndexAction';

        return $actions;
    }

40、编辑\shujujiexi\rests\schedule\IndexAction.php,如图37

图37

 

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */
namespace shujujiexi\rests\schedule;

use Yii;
use yii\rest;
use yii\data\ActiveDataProvider;

/**
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */class IndexAction extends rest\IndexAction
{
    /**
     * @var callable a PHP callable that will be called to prepare a data provider that
     * should return a collection of the models. If not set, [[prepareDataProvider()]] will be used instead.
     * The signature of the callable should be:
     *
     * ```php
     * function ($action) {
     *     // $action is the action object currently running
     * }
     * ```
     *
     * The callable should return an instance of [[ActiveDataProvider]].
     */



    /**
     * Prepares the data provider that should return the requested collection of the models.
     * @return ActiveDataProvider
     */    protected function prepareDataProvider()
    {
        if ($this->prepareDataProvider !== null) {
            return call_user_func($this->prepareDataProvider, $this);
        }

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

        return new ActiveDataProvider([
            'query' => $modelClass::find()->where(['status' => 1]),
        ]);
    }
}

41、在Postman中GET:shujujiexi.kaiqiu_shujujiexi_api.dev/v1/schedules,正确响应,且仅返回status为1的数据,如图38

图38

备注:
1、基于 Gii 生成的模型文件存放于common目录;
2、v1,控制器与模型中的方法建议在\shujujiexi\controllers、\shujujiexi\models中实现;
3、v2,如果需要有不同的功能实现,控制器与模型中的方法建议在\shujujiexi\modules\v1\controllers、\shujujiexi\modules\v1\models中覆盖实现;
4、shujujiexi\rests,其目录结构类似于shujujiexi\views,每一个控制器有其对应的目录;
5、在每一个主要版本 (在相应的模块),使用 Accept HTTP 请求头 确定小版本号编写条件代码来响应相应的次要版本;
// 通过参数
Accept: application/json; version=1.0.0

永夜

View Comments