1、在 api.pcs-stat.localhost 下,一个标准的 RESTful API。方法文件中的代码如下(一位同事所编写)。如图1

图1

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

use common\logics\StatTask;
use Yii;
use api\models\Plan;
use yii\data\ActiveDataProvider;
use yii\data\ArrayDataProvider;
use yii\base\InvalidConfigException;

/**
 * 获取数据大屏的选题管控的任务统计列表:/data-plan-control-tasks ( data-plan-control-task/index )
 *
 * For more details and usage information on IndexAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 */class IndexAction extends \yii\rest\IndexAction
{
    public $dataFilter = [
        'class' => 'yii\data\ActiveDataFilter',
        'searchModel' => 'api\models\StatTaskSearch',
        'attributeMap' => [
            'group_id' => '{{%stat_task}}.[[group_id]]',
            'created_at' => '{{%stat_task}}.[[created_at]]',
        ],
    ];

    /**
     * Prepares the data provider that should return the requested collection of the models.
     * @return array|object|ActiveDataProvider
     * @throws InvalidConfigException
     */    protected function prepareDataProvider()
    {
        $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) {
                    $firstError = '';
                    foreach ($this->dataFilter->getFirstErrors() as $message) {
                        $firstError = $message;
                        break;
                    }
                    return ['code' => 224003, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '224003'), ['first_error' => $firstError]))];
                }
            }
        }

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

        /* @var $modelClass Plan */        $modelClass = $this->modelClass;

        // 任务数量
        $statTask = StatTask::find()->select('sum(plan_task_sum) as plan_task_sum');
        if (!empty($filter)) {
            $statTask->andFilterWhere($filter);
        }
        $statTask = $statTask->one();
        $planTaskCount = $statTask->plan_task_sum;
        if(empty($planTaskCount)){
            $planTaskInfo = [];
        }else{
            // 任务信息
            $planTaskInfo = StatTask::find()
                ->select([
                    StatTask::tableName() . '.name',
                    'sum('.StatTask::tableName().'.plan_task_sum)'.' as planTaskSum',
                ])
                ->groupBy(StatTask::tableName() . '.name')
                ->orderBy(['planTaskSum' => SORT_DESC]);
            if (!empty($filter)) {
                $planTaskInfo->andFilterWhere($filter);
            }
            $planTaskInfo = $planTaskInfo->asArray()->all();
            $num = 0;
            foreach($planTaskInfo as $key=>$value){
                $planTaskInfo[$key]['planTaskSum'] = (int)$value['planTaskSum'];
                $proportion = (float)sprintf("%.4f", $planTaskInfo[$key]['planTaskSum']/$planTaskCount);
                $planTaskInfo[$key]['proportion'] = $proportion;
                if($value == end($planTaskInfo)) {
                    $planTaskInfo[$key]['proportion'] = 1 - $num;
                }else{
                    $num = $num + $planTaskInfo[$key]['proportion'];
                }
            }
        }


        // 设置每页资源数量总数
        // $count = 20;
        // $requestParams['per-page'] = $count;

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

Opening DB connection: mysql:host=62.234.135.47;dbname=pcs_stat

SELECT sum(plan_task_sum) AS `plan_task_sum` FROM `ps_stat_task` WHERE ((`ps_stat_task`.`created_at` >= '1588756760') AND (`ps_stat_task`.`created_at` <= '1589880664')) AND (`ps_stat_task`.`group_id`='015ce30b116ce86058fa6ab4fea4ac63');

SELECT `ps_stat_task`.`name`, sum(`ps_stat_task`.plan_task_sum) AS `planTaskSum` FROM `ps_stat_task` WHERE ((`ps_stat_task`.`created_at` >= '1588756760') AND (`ps_stat_task`.`created_at` <= '1589880664')) AND (`ps_stat_task`.`group_id`='015ce30b116ce86058fa6ab4fea4ac63') GROUP BY `ps_stat_task`.`name` ORDER BY `planTaskSum` DESC;

2、现在计划将此接口迁移至 api.pcs-api.localhost 下,此时,api.pcs-api.localhost 为 RPC 客户端,api.pcs-stat.localhost 为 RPC 服务端。参考:https://www.shuijingwanwq.com/2020/06/23/4273/ 。

3、新建 RPC 服务端文件,rpc/controllers/DataPlanControlTaskController.php

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2020/09/01
 * Time: 10:50
 */
namespace rpc\controllers;

use Yii;
use rpc\models\StatTask;
use yii\base\InvalidConfigException;

/**
 * DataPlanControlTask Controller
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */class DataPlanControlTaskController extends ServerController
{
    public $dataFilter = [
        'class' => 'yii\data\ActiveDataFilter',
        'searchModel' => 'rpc\models\StatTaskSearch',
    ];

    /**
     * 获取数据大屏的选题管控的任务统计列表
     *
     * @param array $data 数据
     *
     * @param string $version 版本号(次版本号与修订号)
     * 格式如下:
     * 2.3
     *
     * @param string $language 区域和语言
     * 格式如下:
     * en-US
     *
     * @return array
     * @throws InvalidConfigException
     */    public function actionIndex(array $data = [], string $version = '', string $language = '')
    {
        if (!empty($language)) {
            Yii::$app->language = $language;
        }

        $filter = null;
        if ($this->dataFilter !== null) {
            $this->dataFilter = Yii::createObject($this->dataFilter);
            if ($this->dataFilter->load($data)) {
                $filter = $this->dataFilter->build();
                if ($filter === false) {
                    $firstError = '';
                    foreach ($this->dataFilter->getFirstErrors() as $message) {
                        $firstError = $message;
                        break;
                    }
                    return ['code' => 230003, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '230003'), ['first_error' => $firstError]))];
                }
            }
        }

        /* @var $modelClass StatTask */        $modelClass = $this->modelClass;

        // 任务数量
        $statTask = $modelClass::find()->select('sum(plan_task_sum) as plan_task_sum');
        if (!empty($filter)) {
            $statTask->andFilterWhere($filter);
        }
        $statTask = $statTask->one();
        $planTaskCount = $statTask->plan_task_sum;
        if (empty($planTaskCount)) {
            $planTaskInfo = [];
        } else {
            // 任务信息
            $planTaskInfo = StatTask::find()
                ->select([
                    StatTask::tableName() . '.name',
                    'sum('.StatTask::tableName().'.plan_task_sum)'.' as planTaskSum',
                ])
                ->groupBy(StatTask::tableName() . '.name')
                ->orderBy(['planTaskSum' => SORT_DESC]);
            if (!empty($filter)) {
                $planTaskInfo->andFilterWhere($filter);
            }
            $planTaskInfo = $planTaskInfo->asArray()->all();
            $num = 0;
            foreach ($planTaskInfo as $key => $value) {
                $planTaskInfo[$key]['planTaskSum'] = (int) $value['planTaskSum'];
                $proportion = (float) sprintf("%.4f", $planTaskInfo[$key]['planTaskSum'] / $planTaskCount);
                $planTaskInfo[$key]['proportion'] = $proportion;
                if ($value == end($planTaskInfo)) {
                    $planTaskInfo[$key]['proportion'] = 1 - $num;
                } else {
                    $num = $num + $planTaskInfo[$key]['proportion'];
                }
            }
        }

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

4、新建 RPC 客户端的模型文件,common/logics/rpc/stat/StatTask.php

<?php

namespace common\logics\rpc\stat;

use Yii;
use common\logics\rpc\Model;

/**
 * 任务统计
 */class StatTask extends Model
{
    const CONTROLLER_ID = 'data-plan-control-task'; // 控制器ID

    /**
     * 获取数据大屏的选题管控的任务统计列表
     *
     * @param array $data 数据
     *
     * @param string $version 版本号(次版本号与修订号)
     * 格式如下:
     * 2.3
     *
     * @param string $language 区域和语言
     * 格式如下:
     * en-US
     *
     * @return mixed
     * @throws \Exception
     */    public function index(array $data, string $version, string $language)
    {
        $actionId = 'index';
        return self::client(self::CONTROLLER_ID, $actionId)->$actionId($data, $version, $language);
    }

}

5、新建 RPC 客户端的方法文件,api/rests/data_plan_control_task/IndexAction.php

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

use Yii;
use api\models\rpc\stat\StatTask;
use yii\data\ActiveDataProvider;
use yii\data\ArrayDataProvider;
use yii\base\InvalidConfigException;
use yii\web\ServerErrorHttpException;

/**
 * 获取数据大屏的选题管控的任务统计列表:/data-plan-control-tasks(data-plan-control-task/index)
 *
 * For more details and usage information on IndexAction, see the [guide article on rest controllers](guide:rest-controllers).
 *
 */class IndexAction extends \yii\rest\IndexAction
{
    public $dataFilter = [
        'class' => 'yii\data\ActiveDataFilter',
        'searchModel' => 'api\models\StatTaskSearch',
    ];

    /**
     * Prepares the data provider that should return the requested collection of the models.
     * @return array|mixed|object|ActiveDataProvider
     * @throws InvalidConfigException
     * @throws ServerErrorHttpException
     */    protected function prepareDataProvider()
    {
        $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) {
                    $firstError = '';
                    foreach ($this->dataFilter->getFirstErrors() as $message) {
                        $firstError = $message;
                        break;
                    }
                    return ['code' => 224003, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '224003'), ['first_error' => $firstError]))];
                }
            }
        }

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

        /* @var $modelClass StatTask */        $modelClass = $this->modelClass;

        // 内容协商
        $response = Yii::$app->response;
        $acceptParams = $response->acceptParams;
        if (isset($acceptParams['version'])) {
            $version = $acceptParams['version'];
        } else {
            $version = '';
        }

        // 获取数据大屏的选题管控的任务统计列表
        $rpcStatStatTask = new $modelClass();
        $data = $rpcStatStatTask->index($requestParams, $version, Yii::$app->language);

        if ($data['code'] !== 10000) {
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '202087'), ['code' => $data['code'], 'message' => $data['message']])), 202087);
        }



        // 设置每页资源数量默认为资源总数
        $count = count($data['data']);
        if ($count !== 0) {
            $requestParams['per-page'] = $count;
        }

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

6、分页参数的支持,有待于后续实现。此接口无需要支持分页参数的自定义。GET 请求:http://api.pcs-api.localhost/v1/data-plan-control-tasks?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=d31652b0f940b810da05d9755d20c7a1&filter[created_at][gte]=1588756760&filter[created_at][lte]=1589880664&filter[group_id]=015ce30b116ce86058fa6ab4fea4ac63 。符合预期。如图2

图2

{
    "code": 10000,
    "message": "获取数据大屏的选题管控的任务统计列表成功",
    "data": {
        "items": [
            {
                "name": "采访任务",
                "plan_task_sum": 17,
                "proportion": 0.2537
            },
            {
                "name": "互联网发布",
                "plan_task_sum": 14,
                "proportion": 0.209
            },
            {
                "name": "自定义一",
                "plan_task_sum": 13,
                "proportion": 0.194
            },
            {
                "name": "手动任务",
                "plan_task_sum": 9,
                "proportion": 0.1343
            },
            {
                "name": "电视播出",
                "plan_task_sum": 8,
                "proportion": 0.1194
            },
            {
                "name": "自定义二",
                "plan_task_sum": 3,
                "proportion": 0.0448
            },
            {
                "name": "自定义八",
                "plan_task_sum": 2,
                "proportion": 0.0299
            },
            {
                "name": "自定义六",
                "plan_task_sum": 1,
                "proportion": 0.0149
            }
        ],
        "_links": {
            "self": {
                "href": "http://api.pcs-api.localhost/v1/data-plan-control-tasks?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=d31652b0f940b810da05d9755d20c7a1&filter%5Bcreated_at%5D%5Bgte%5D=1588756760&filter%5Bcreated_at%5D%5Blte%5D=1589880664&filter%5Bgroup_id%5D=015ce30b116ce86058fa6ab4fea4ac63&page=1&per-page=8"
            }
        },
        "_meta": {
            "totalCount": 8,
            "pageCount": 1,
            "currentPage": 1,
            "perPage": 8
        }
    }
}

7、查看请求日志,本质上是先请求:api.pcs-api.localhost,再请求:rpc.pcs-stat.localhost。如图3

图3

 

永夜