基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建远程过程调用应用(实现基于 Hprose 2.0 for PHP 的 RPC 服务端),在 rpc 目录中实现 页面 的相应 RPC 服务,且在 api 目录中的 API 实现 RPC 客户端 (八) (2)

1、在 rpc 目录中实现 页面 的相应 RPC 服务,创建 远程过程调用 HTTP 服务器,新建 /rpc/controllers/ServerController.php

<?php
/**
 * Created by PhpStorm.
 * User: WangQiang
 * Date: 2018/08/01
 * Time: 18:02
 */

namespace rpc/controllers;

use Yii;
use yii/web/Controller;
use Hprose/Yii/Server;

/**
 * 远程过程调用 HTTP 服务器
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class ServerController extends Controller
{
    public $enableCsrfValidation = false;

    public function beforeAction($action)
    {
        parent::beforeAction($action);
        $server = new Server();
        $server->addMethod($action->actionMethod, $this, $action->controller->id . '_' . $action->id);
        $server->start();
    }
}

2、新建页面模型 /rpc/models/Page.php

<?php

namespace rpc/models;


class Page extends /common/logics/Page
{

}

3、新建页面控制器,/rpc/controllers/PageController.php

<?php
/**
 * Created by PhpStorm.
 * User: WangQiang
 * Date: 2018/08/01
 * Time: 15:01
 */

namespace rpc/controllers;

use Yii;
use rpc/models/Page;

/**
 * Page Controller
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class PageController extends ServerController
{
    /**
     * 创建页面
     *
     * @param array $data 数据
     *
     * @param string $version 版本号(次版本号与修订号)
     * 格式如下:
     * 2.3
     *
     * @param string $language 区域和语言
     * 格式如下:
     * en-US
     *
     * @return mixed
     */
    public function actionCreate(array $data, string $version = '', string $language = '')
    {
        return $data;
        //echo 1;
        //exit;
        //$fileName = date('Y-m-d-H-i-s', time()) . '-' . microtime(true);
        //file_put_contents('./../runtime/' . $fileName . '.txt', '0');
        //return 1;
    }
}

4、然后在浏览器端打开网址:http://rpc.github-shuijingwan-yii2-app-advanced.localhost/page/create ,看到以下输出:Fa2{u#s11″page_create”}z,符合预期

5、通过工厂方法 create 创建客户端,编辑 /api/rests/page/CreateAction.php

<?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;
use Hprose/Http/Client;

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

        $client = Client::create('http://rpc.github-shuijingwan-yii2-app-advanced.localhost/page/create', false);
        $page = $client->page_create([
            'title' => 'title',
            'body' => 'body',
        ]);

        print_r($page);
        exit;

        /* @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;
                break;
            }
            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('success', '10805'), 'data' => $model];
    }
}

6、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应失败

{
    "name": "Exception",
    "message": "28: Operation timed out after 30000 milliseconds with 0 bytes received",
    "code": 0,
    "type": "Exception",
    "file": "E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Http//Client.php",
    "line": 276,
    "stack-trace": [
        "#0 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Http//Client.php(295): Hprose//Http//Client->syncSendAndReceive('Cs11/"page_creat...', Object(stdClass))",
        "#1 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(539): Hprose//Http//Client->sendAndReceive('Cs11/"page_creat...', Object(stdClass))",
        "#2 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(109): Hprose//Client->afterFilterHandler('Cs11/"page_creat...', Object(stdClass))",
        "#3 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(504): Hprose//Client->Hprose//{closure}('Cs11/"page_creat...', Object(stdClass))",
        "#4 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(518): Hprose//Client->syncBeforeFilterHandler('Cs11/"page_creat...', Object(stdClass))",
        "#5 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(106): Hprose//Client->beforeFilterHandler('Cs11/"page_creat...', Object(stdClass))",
        "#6 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(476): Hprose//Client->Hprose//{closure}('Cs11/"page_creat...', Object(stdClass))",
        "#7 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(489): Hprose//Client->syncInvokeHandler('page_create', Array, Object(stdClass))",
        "#8 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(103): Hprose//Client->invokeHandler('page_create', Array, Object(stdClass))",
        "#9 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(608): Hprose//Client->Hprose//{closure}('page_create', Array, Object(stdClass))",
        "#10 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//hprose//hprose//src//Hprose//Client.php(438): Hprose//Client->invoke('page_create', Array)",
        "#11 E://wwwroot//github-shuijingwan-yii2-app-advanced//api//rests//page//CreateAction.php(49): Hprose//Client->__call('page_create', Array)",
        "#12 [internal function]: api//rests//page//CreateAction->run()",
        "#13 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//yiisoft//yii2//base//Action.php(94): call_user_func_array(Array, Array)",
        "#14 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//yiisoft//yii2//base//Controller.php(157): yii//base//Action->runWithParams(Array)",
        "#15 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//yiisoft//yii2//base//Module.php(528): yii//base//Controller->runAction('create', Array)",
        "#16 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//yiisoft//yii2//web//Application.php(103): yii//base//Module->runAction('v1/page/create', Array)",
        "#17 E://wwwroot//github-shuijingwan-yii2-app-advanced//vendor//yiisoft//yii2//base//Application.php(386): yii//web//Application->handleRequest(Object(yii//web//Request))",
        "#18 E://wwwroot//github-shuijingwan-yii2-app-advanced//api//web//index.php(17): yii//base//Application->run()",
        "#19 {main}"
    ]
}

7、出现以上原因是因为 Windows 下 nginx php 环境,不支持并发的原因,当同时访问多个域名,并且同时指向你本地服务的时候,就不支持并发了。nginx.conf 里面 对不同 server 修改 fastcgi_pass 的端口号,启动多个 php-cgi。如图1

出现以上原因是因为 Windows 下 nginx php 环境,不支持并发的原因,当同时访问多个域名,并且同时指向你本地服务的时候,就不支持并发了。nginx.conf 里面 对不同 server 修改 fastcgi_pass 的端口号,启动多个 php-cgi。

图1

## FRONTEND ##
server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80; ## listen for ipv4
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name www.github-shuijingwan-yii2-app-advanced.localhost;
    root        E:/wwwroot/github-shuijingwan-yii2-app-advanced/frontend/web;
    index       index.php;

    access_log  logs/www.github-shuijingwan-yii2-app-advanced.localhost.access.log;
    error_log   logs/www.github-shuijingwan-yii2-app-advanced.localhost.error.log;

	location / {
		# Redirect everything that isn't a real file to index.php
		try_files $uri $uri/ /index.php$is_args$args;
	}

	# uncomment to avoid processing of calls to non-existing static files by Yii
	#location ~ /.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
	#    try_files $uri =404;
	#}
	#error_page 404 /404.html;

	# deny accessing php files for the /assets directory
	location ~ ^/assets/.*/.php$ {
		deny all;
	}

	location ~ /.php$ {
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass 127.0.0.1:9000;
		#fastcgi_pass unix:/var/run/php5-fpm.sock;
		try_files $uri =404;
	}

	location ~* //. {
		deny all;
	}
}

## BACKEND ##
server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80; ## listen for ipv4
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name backend.github-shuijingwan-yii2-app-advanced.localhost;
    root        E:/wwwroot/github-shuijingwan-yii2-app-advanced/backend/web;
    index       index.php;

    access_log  logs/backend.github-shuijingwan-yii2-app-advanced.localhost.access.log;
    error_log   logs/backend.github-shuijingwan-yii2-app-advanced.localhost.error.log;

	location / {
		# Redirect everything that isn't a real file to index.php
		try_files $uri $uri/ /index.php$is_args$args;
	}

	# uncomment to avoid processing of calls to non-existing static files by Yii
	#location ~ /.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
	#    try_files $uri =404;
	#}
	#error_page 404 /404.html;

	# deny accessing php files for the /assets directory
	location ~ ^/assets/.*/.php$ {
		deny all;
	}

	location ~ /.php$ {
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass 127.0.0.1:9000;
		#fastcgi_pass unix:/var/run/php5-fpm.sock;
		try_files $uri =404;
	}

	location ~* //. {
		deny all;
	}
}

## API ##
server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80; ## listen for ipv4
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name api.github-shuijingwan-yii2-app-advanced.localhost;
    root        E:/wwwroot/github-shuijingwan-yii2-app-advanced/api/web;
    index       index.php;

    access_log  logs/api.github-shuijingwan-yii2-app-advanced.localhost.access.log;
    error_log   logs/api.github-shuijingwan-yii2-app-advanced.localhost.error.log;

	location / {
		# Redirect everything that isn't a real file to index.php
		try_files $uri $uri/ /index.php$is_args$args;
	}

	# uncomment to avoid processing of calls to non-existing static files by Yii
	#location ~ /.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
	#    try_files $uri =404;
	#}
	#error_page 404 /404.html;

	# deny accessing php files for the /assets directory
	location ~ ^/assets/.*/.php$ {
		deny all;
	}

	location ~ /.php$ {
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass 127.0.0.1:9001;
		#fastcgi_pass unix:/var/run/php5-fpm.sock;
		try_files $uri =404;
	}

	location ~* //. {
		deny all;
	}
}

## RPC ##
server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80; ## listen for ipv4
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name rpc.github-shuijingwan-yii2-app-advanced.localhost;
    root        E:/wwwroot/github-shuijingwan-yii2-app-advanced/rpc/web;
    index       index.php;

    access_log  logs/rpc.github-shuijingwan-yii2-app-advanced.localhost.access.log;
    error_log   logs/rpc.github-shuijingwan-yii2-app-advanced.localhost.error.log;

	location / {
		# Redirect everything that isn't a real file to index.php
		try_files $uri $uri/ /index.php$is_args$args;
	}

	# uncomment to avoid processing of calls to non-existing static files by Yii
	#location ~ /.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
	#    try_files $uri =404;
	#}
	#error_page 404 /404.html;

	# deny accessing php files for the /assets directory
	location ~ ^/assets/.*/.php$ {
		deny all;
	}

	location ~ /.php$ {
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass 127.0.0.1:9000;
		#fastcgi_pass unix:/var/run/php5-fpm.sock;
		try_files $uri =404;
	}

	location ~* //. {
		deny all;
	}
}

## MISC ##

### WWW Redirect ###
server {
    listen       80;
    server_name  github-shuijingwan-yii2-app-advanced.localhost;
    return       301 http://www.github-shuijingwan-yii2-app-advanced.localhost$request_uri;
}

8、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-a-client.localhost/v1/pages ,响应成功

Array
(
    [title] => title
    [body] => body
)

9、新建模块 v1,基于模块实现版本控制,打开:http://www.github-shuijingwan-yii2-app-advanced.localhost/gii/module ,生成模块 v1,如图2

新建模块 v1,基于模块实现版本控制,打开:http://www.github-shuijingwan-yii2-app-advanced.localhost/gii/module ,生成模块 v1

图2

10、重命名 /rpc/modules/v1/controllers/DefaultController.php 为 /rpc/modules/v1/controllers/PageController.php

<?php

namespace rpc/modules/v1/controllers;

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

11、删除 /rpc/modules/v1/views

12、复制 /api/models/Page.php、/api/models/PageQuery.php、/api/models/PageSearch.php 为 /rpc/models/Page.php、/rpc/models/PageQuery.php、/rpc/models/PageSearch.php,调整命名空间

13、复制 /api/modules/v1/models/Page.php、/api/modules/v1/models/PageQuery.php、/api/modules/v1/models/PageSearch.php 为 /rpc/modules/v1/models/Page.php、/rpc/modules/v1/models/PageQuery.php、/rpc/modules/v1/models/PageSearch.php,调整命名空间

14、编辑 /rpc/config/main.php,将模块加入到应用主体配置的 modules 属性的列表中

    'modules' => [
        'v1' => [
            'class' => rpc/modules/v1/Module::class,
        ],
    ],

15、在浏览器端打开网址:http://rpc.github-shuijingwan-yii2-app-advanced.localhost/v1/page/create ,看到以下输出:Fa2{u#s11″page_create”}z,符合预期

16、通过工厂方法 create 创建客户端,编辑 /api/rests/page/CreateAction.php,调整 HTTP 服务地址

        $client = Client::create('http://rpc.github-shuijingwan-yii2-app-advanced.localhost/v1/page/create', false);
        $page = $client->page_create([
            'title' => 'title',
            'body' => 'body',
        ]);

        print_r($page);
        exit;

17、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应正常

Array
(
    [title] => title
    [body] => body
)

18、编辑 /environments/dev/common/config/params-local.php、/environments/prod/common/config/params-local.php

<?php
return [
    // RPC HTTP 服务地址
    'rpc' => [
        'hostInfo' => 'http://rpc.github-shuijingwan-yii2-app-advanced.localhost', // HOME URL
        'baseUrl' => '/v1', // BASE URL
    ],
];

19、新建 RPC 客户端的基础类,/common/logics/rpc/Model.php

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/08/02
 * Time: 13:12
 */

namespace common/logics/rpc;

use Yii;
use Hprose/Http/Client;

/**
 * RPC 客户端的基础类
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class Model extends /yii/base/Model
{
    /**
     * 创建一个同步的 HTTP 客户端
     *
     * @param string $controllerId 控制器ID
     * 格式如下:
     * page
     *
     * @param string $actionId 方法ID
     * 格式如下:
     * create
     *
     * @return object $client 同步的 HTTP 客户端
     */
    public static function client($controllerId, $actionId)
    {
        $url = Yii::$app->params['rpc']['hostInfo'] . Yii::$app->params['rpc']['baseUrl'];
        $client = Client::create($url . '/' . $controllerId . '/' . $actionId, false);
        return $client->$controllerId;
    }
}

20、新建页面模型的公共逻辑类,/common/logics/rpc/Page.php,定义模型属性、场景(块赋值)、验证规则(初步验证请求数据,以避免明显不符合规则的数据,穿透至 RPC 服务端)

<?php

namespace common/logics/rpc;

use Yii;

/**
 * 页面模型
 */
class Page extends Model
{
    const STATUS_DELETED = -1; //状态:删除
    const STATUS_DISABLED = 0; //状态:禁用
    const STATUS_DRAFT = 1; //状态:草稿
    const STATUS_PUBLISHED = 2; //状态:发布

    const CONTROLLER_ID = 'page'; //控制器ID

    const SCENARIO_CREATE = 'create';

    public $slug;
    public $title;
    public $body;
    public $view;
    public $status;

    /**
     * {@inheritdoc}
     */
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios[self::SCENARIO_CREATE] = ['slug', 'title', 'body', 'view', 'status'];

        return $scenarios;
    }

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

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'slug' => Yii::t('model/rpc/page', 'Slug'),
            'title' => Yii::t('model/rpc/page', 'Title'),
            'body' => Yii::t('model/rpc/page', 'Body'),
            'view' => Yii::t('model/rpc/page', 'View'),
            'status' => Yii::t('model/rpc/page', 'Status'),
        ];
    }

    /**
     * 创建页面
     *
     * @param array $data 数据
     *
     * @param string $version 版本号(次版本号与修订号)
     * 格式如下:
     * 2.3
     *
     * @param string $language 区域和语言
     * 格式如下:
     * en-US
     *
     * @return array
     */
    public function create(array $data, string $version, string $language)
    {
        $actionId = 'create';
        return self::client(self::CONTROLLER_ID, $actionId)->$actionId($data, $version, $language);
    }

}

21、新建 /api/models/rpc/Page.php

<?php

namespace api/models/rpc;

class Page extends /common/logics/rpc/Page
{

}

22、新建 /api/modules/v1/models/rpc/Page.php

<?php
/**
 * Created by PhpStorm.
 * User: WangQiang
 * Date: 2018/08/02
 * Time: 13:04
 */

namespace api/modules/v1/models/rpc;


class Page extends /api/models/rpc/Page
{

}

23、编辑 /api/modules/v1/controllers/PageController.php,指定模型类

<?php

namespace api/modules/v1/controllers;

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

23、编辑 /common/logics/Page.php,定义场景

<?php

namespace common/logics;

use Yii;
use yii/behaviors/SluggableBehavior;
use yii/behaviors/TimestampBehavior;
use yii2tech/ar/softdelete/SoftDeleteBehavior;
use yii/helpers/ArrayHelper;

class Page extends /common/models/Page
{
    const STATUS_DELETED = -1; //状态:删除
    const STATUS_DISABLED = 0; //状态:禁用
    const STATUS_DRAFT = 1; //状态:草稿
    const STATUS_PUBLISHED = 2; //状态:发布

    const SCENARIO_CREATE = 'create';

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'timestampBehavior' => [
                'class' => TimestampBehavior::className(),
                'attributes' => [
                    self::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    self::EVENT_BEFORE_UPDATE => 'updated_at',
                    SoftDeleteBehavior::EVENT_BEFORE_SOFT_DELETE => 'updated_at',
                ]
            ],
            'slug' => [
                'class' => SluggableBehavior::className(),
                'attribute' => 'title',
                'ensureUnique' => true,
                'immutable' => true
            ],
            'softDeleteBehavior' => [
                'class' => SoftDeleteBehavior::className(),
                'softDeleteAttributeValues' => [
                    'status' => self::STATUS_DELETED
                ],
            ],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios[self::SCENARIO_CREATE] = ['slug', 'title', 'body', 'view', 'status'];

        return $scenarios;
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        $rules = [
            [['title', 'body'], 'required'],
            [['slug'], 'unique'],
            ['view', 'default', 'value' => 0],
            ['status', 'default', 'value' => self::STATUS_DRAFT],
        ];
        $parentRules = parent::rules();

        unset($parentRules[0]);

        return ArrayHelper::merge($rules, $parentRules);
    }

    /**
     * {@inheritdoc}
     * @return PageQuery the active query used by this AR class.
     */
    public static function find()
    {
        return new PageQuery(get_called_class());
    }

}

24、编辑 /rpc/config/main.php,以支持国际化

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

25、编辑 /api/rests/page/CreateAction.php

<?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';

    public $createScenario = 'create';


    /**
     * 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->createScenario,
        ]);

        $model->load(Yii::$app->getRequest()->getBodyParams(), '');

        // 模型转换成数组
        $data = $model->attributes;

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

        if ($model->validate()) {
            $data = $model->create($data, $version, Yii::$app->language);
            if ($data['code'] === 10000) {
                $response = Yii::$app->getResponse();
                $response->setStatusCode(201);
                $id = $data['data']['id'];
                $response->getHeaders()->set('Location', Url::toRoute([$this->viewAction, 'id' => $id], true));
            }
            return $data;
        } elseif ($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]))];
        } elseif (!$model->hasErrors()) {
            throw new ServerErrorHttpException('Failed to create the object for unknown reason.');
        }
    }
}

26、编辑 /rpc/controllers/PageController.php

<?php
/**
 * Created by PhpStorm.
 * User: WangQiang
 * Date: 2018/08/01
 * Time: 15:01
 */

namespace rpc/controllers;

use Yii;
use yii/web/ServerErrorHttpException;

/**
 * Page Controller
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */
class PageController extends ServerController
{
    public $createScenario = 'create';

    /**
     * 创建页面
     *
     * @param array $data 数据
     *
     * @param string $version 版本号(次版本号与修订号)
     * 格式如下:
     * 2.3
     *
     * @param string $language 区域和语言
     * 格式如下:
     * en-US
     *
     * @return mixed
     */
    public function actionCreate(array $data, string $version = '', string $language = '')
    {
        if (!empty($language)) {
            Yii::$app->language = $language;
        }

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

        if ($model->load($data, '') && $model->save()) {
            $data = $model->attributes;
        } elseif ($model->hasErrors()) {
            foreach ($model->getFirstErrors() as $message) {
                $firstErrors = $message;
                break;
            }
            return ['code' => 25004, 'message' => Yii::t('error', Yii::t('error', Yii::t('error', '25004'), ['firstErrors' => $firstErrors]))];
        } elseif (!$model->hasErrors()) {
            throw new ServerErrorHttpException('Failed to create the object for unknown reason1.');
        }

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

27、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应失败

{
	"title":"title-20180731-5"
}

注:接口模型验证失败

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

28、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应失败

{
	"title":"title-20180731-5",
	"body":"title-20180731-5",
	"slug":"title-20180731-5"
}

注:RPC 模型验证失败

{
    "code": 25004,
    "message": "数据验证失败:别名的值/"title-20180731-5/"已经被占用了。"
}

29、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应成功

{
	"title":"title-20180731-5",
	"body":"title-20180731-5"
}
{
    "code": 10000,
    "message": "创建页面成功",
    "data": {
        "id": 12,
        "slug": "title-20180731-5-7",
        "title": "title-20180731-5",
        "body": "title-20180731-5",
        "view": 0,
        "status": 1,
        "created_at": 1533205467,
        "updated_at": 1533205467
    }
}

 

 

 

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/181535.html

(0)
上一篇 2021年11月1日
下一篇 2021年11月1日

相关推荐

发表回复

登录后才能评论