基于 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?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
1 2 3 4 5 6 7 8 9 | <?php namespace rpc\models; class Page extends \common\logics\Page { } |
3、新建页面控制器,\rpc\controllers\PageController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | <?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 ,响应失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | { "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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | ## 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 ,响应成功
1 2 3 4 5 | 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
1 2 3 4 5 6 7 8 9 10 11 | <?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 属性的列表中
1 2 3 4 5 | '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 服务地址
1 2 3 4 5 6 7 8 | $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 ,响应正常
1 2 3 4 5 | Array ( [title] => title [body] => body ) |
18、编辑 \environments\dev\common\config\params-local.php、\environments\prod\common\config\params-local.php
1 2 3 4 5 6 7 8 | <?php return [ // RPC HTTP 服务地址 'rpc' => [ 'baseUrl' => '/v1' , // BASE URL ], ]; |
19、新建 RPC 客户端的基础类,\common\logics\rpc\Model.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <?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 服务端)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | <?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
1 2 3 4 5 6 7 8 | <?php namespace api\models\rpc; class Page extends \common\logics\rpc\Page { } |
22、新建 \api\modules\v1\models\rpc\Page.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?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,指定模型类
1 2 3 4 5 6 7 8 9 10 11 | <?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,定义场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | <?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,以支持国际化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | '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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | <?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <?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 ,响应失败
1 2 3 | { "title":"title-20180731-5" } |
注:接口模型验证失败
1 2 3 4 | { "code": 20004, "message": "数据验证失败:内容不能为空。" } |
28、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应失败
1 2 3 4 5 | { "title":"title-20180731-5", "body":"title-20180731-5", "slug":"title-20180731-5" } |
注:RPC 模型验证失败
1 2 3 4 | { "code": 25004, "message": "数据验证失败:别名的值\"title-20180731-5\"已经被占用了。" } |
29、在 Postman 中 POST http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/pages ,响应成功
1 2 3 4 | { "title":"title-20180731-5", "body":"title-20180731-5" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "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 } } |
近期评论