基于 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 } }
近期评论