1. Implement the corresponding RPC service for Page in the rpc directory, create the Remote Procedure Call HTTP server, and create \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. Create the Page model \rpc\models\Page.php
<?php
namespace rpc\models;
class Page extends \common\logics\Page
{
}
3. Create the Page controller \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. Then open the URL http://rpc.github-shuijingwan-yii2-app-advanced.localhost/page/create in the browser. You will see the following output: Fa2{u#s11″page_create”}z, which is as expected
5. Create the client via the factory method create. Edit \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. In Postman, POST to http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages. The response fails
{
"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. The reason for the above is that the Windows nginx PHP environment does not support concurrency. When accessing multiple domains simultaneously that all point to your local service, concurrency is not supported. In nginx.conf, modify the fastcgi_pass port number for different servers and start multiple php-cgi processes. See Figure 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. In Postman, POST to http://api.github-shuijingwan-yii2-app-a-client.localhost/v1/pages. The response succeeds
Array
(
[title] => title
[body] => body
)
9. Create the v1 module to implement version control based on modules. Open http://www.github-shuijingwan-yii2-app-advanced.localhost/gii/module to generate the v1 module. See Figure 2

10. Rename \rpc\modules\v1\controllers\DefaultController.php to \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. Delete \rpc\modules\v1\views
12. Copy \api\models\Page.php, \api\models\PageQuery.php, and \api\models\PageSearch.php to \rpc\models\Page.php, \rpc\models\PageQuery.php, and \rpc\models\PageSearch.php, and adjust the namespaces
13. Copy \api\modules\v1\models\Page.php, \api\modules\v1\models\PageQuery.php, and \api\modules\v1\models\PageSearch.php to \rpc\modules\v1\models\Page.php, \rpc\modules\v1\models\PageQuery.php, and \rpc\modules\v1\models\PageSearch.php, and adjust the namespaces
14. Edit \rpc\config\main.php to add the module to the modules property list in the application configuration
'modules' => [
'v1' => [
'class' => rpc\modules\v1\Module::class,
],
],
15. Open the URL http://rpc.github-shuijingwan-yii2-app-advanced.localhost/v1/page/create in the browser. You will see the following output: Fa2{u#s11″page_create”}z, which is as expected
16. Create the client via the factory method create. Edit \api\rests\page\CreateAction.php and adjust the HTTP service address
$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. In Postman, POST to http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages. The response is normal
Array
(
[title] => title
[body] => body
)
18. Edit \environments\dev\common\config\params-local.php and \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. Create the base class for the RPC client: \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. Create the common logic class for the Page model: \common\logics\rpc\Page.php. Define model properties, scenarios (massive assignment), and validation rules (perform preliminary validation of request data to prevent obviously invalid data from penetrating to the RPC server)
<?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. Create \api\models\rpc\Page.php
<?php
namespace api\models\rpc;
class Page extends \common\logics\rpc\Page
{
}
22. Create \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. Edit \api\modules\v1\controllers\PageController.php to specify the model class
<?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. Edit \common\logics\Page.php to define scenarios
<?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. Edit \rpc\config\main.php to support internationalization
'i18n' => [
'translations' => [
'model/*'=> [
'class' => 'yii\i18n\PhpMessageSource',
'forceTranslation' => true,
'basePath'=>'@common/messages',
'fileMap'=>[
],
],
'*'=> [
'class' => 'yii\i18n\PhpMessageSource',
'forceTranslation' => true,
'basePath'=>'@rpc/messages',
'fileMap'=>[
],
],
],
],
],
25. Edit \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. Edit \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. In Postman, POST to http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages. The response fails
{
"title":"title-20180731-5"
}
Note: Interface model validation failed
{
"code": 20004,
"message": "数据验证失败:内容不能为空。"
}
28. In Postman, POST to http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages. The response fails
{
"title":"title-20180731-5",
"body":"title-20180731-5",
"slug":"title-20180731-5"
}
Note: RPC model validation failed
{
"code": 25004,
"message": "数据验证失败:别名的值\"title-20180731-5\"已经被占用了。"
}
29. In Postman, POST to http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages. The response succeeds
{
"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
}
}
