基于 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
## 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
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
}
}


近期评论