Yii2中Restful API原理實(shí)例分析
本文實(shí)例分析了Yii2中Restful API原理。分享給大家供大家參考,具體如下:
Yii2 有個很重要的特性是對 Restful API的默認(rèn)支持, 通過短短的幾個配置就可以實(shí)現(xiàn)簡單的對現(xiàn)有Model的RESTful API
這里通過分析rest部分源碼,簡單剖析下yii2 實(shí)現(xiàn) restful 的原理,并通過一些定制實(shí)現(xiàn) 對 關(guān)聯(lián)模型的RESTful api 操作。
~ 代表 extends from 的關(guān)系
| | rest/
| | |-Action.php ~ `\yii\base\Action`
| | |-Controller.php ~ `\yii\web\Controller`
| | | |-ActiveController.php ~ `rest\Controller`
| | |-Serializer.php ~ `yii\base\Component`
| | |-UrlRule.php ~ `yii\web\CompositeUrlRule`
| | |-CreateAction.php ~ `rest\Action`
| | |-DeleteAction.php ~ `rest\Action`
| | |-IndexAction.php ~ `rest\Action`
| | |-OptionsAction.php ~ `rest\Action`
| | |-UpdateAction.php ~ `rest\Action`
| | |-ViewAction.php ~ `rest\Action`
1. rest/Controller ~ \yii\web\Controller
Controller是 RESTful API 控制器類的基類
它在一個API請求的控制周期中一次實(shí)現(xiàn)了下面的步驟 1~5:
① 解析響應(yīng)的內(nèi)容格式
② 校驗(yàn)請求方法
③ 檢驗(yàn)用戶權(quán)限
④ 限制速度
⑤ 格式化響應(yīng)數(shù)據(jù)
use yii\filters\auth\CompositeAuth; use yii\filters\ContentNegotiator; use yii\filters\RateLimiter; use yii\web\Response; use yii\filters\VerbFilter; /** * Controller is the base class for RESTful API controller classes. * * Controller implements the following steps in a RESTful API request handling cycle * 1. Resolving response format (see [[ContentNegotiator]]); * 2. Validating request method (see [[verbs()]]). * 3. Authenticating user (see [[\yii\filters\auth\AuthInterface]]); * 4. Rate limiting (see [[RateLimiter]]); * 5. Formatting response data (see [[serializeData()]]) behaviors contentNegotiator verbFilter authenticator rateLimiter afterAction serializeData Yii::createObject($this->serializer)->serialize($data) verbs [] */ class Controller extends \yii\web\Controller { public $serializer = 'yii\rest\Serializer'; public $enableCsrfValidation = false; public function behaviors() { return [ 'contentNegotiator' => [ 'class' => ContentNegotiator::className(), 'formats' => [ 'application/json' => Response::FORMAT_JSON, 'application/xml' => Response::FORMAT_XML, ], ], 'verbFilter' => [ 'class' => VerbFilter::className(), 'actions' => $this->verbs(), ], 'authenticator' => [ 'class' => CompositeAuth::className(), ], 'rateLimiter' => [ 'class' => RateLimiter::className(), ], ] } public function verbs() { return []; } public function serializeData($data) { return Yii::createObject($this->serializer)->serialize($data); } public function afterAction($action, $result) { $result = parent::afterAction($action, $result); return $this->serializeData($result); } }
2. rest/ActiveController ~ rest/Controller
ActiveController 實(shí)現(xiàn)了一系列的和 ActiveRecord 互通數(shù)據(jù)的RESTful方法
ActiveRecord 的類名由 modelClass 變量指明, yii\db\ActiveRecordInterface ???
默認(rèn)的, 支持下面的方法:
* - `index`: list of models
* - `view`: return the details of a model
* - `create`: create a new model
* - `update`: update an existing model
* - `delete`: delete an existing model
* - `options`: return the allowed HTTP methods
可以通過覆蓋 actions() 并且 unsetting 響應(yīng)的 action 來禁用這些默認(rèn)的動作。
要增加一個新的動作, 覆蓋 actions() 向其末尾增加一個新的 action class 或者 是一個新的 action method
注意一點(diǎn),確保你同時也覆蓋了 verbs() 方法來聲明這個新的動作支持那些HTTP Method
也需要覆蓋checkAccess() 來檢查當(dāng)前用戶是否有權(quán)限來執(zhí)行響應(yīng)的某個動作。
根據(jù)上面的說明再寫一遍 Controller
class ActiveController extends Controller { public #modelClass; public $updateScenario = Model::SCENARIO_DEFAULT; public $createScenario = Model::SCENARIO_DEFAULT; public function init() { parent::init(); if($this->modelClass == null){ throw new InvalidConfigException('The "modelClass" property must be set.'); } } public function actions() { return [ 'index' => [ 'class' => 'app\controllers\rest\IndexAction', 'modelClass' => $this->modelClass, 'checkAccess' => [$this, 'checkAccess'], ], 'view'... 'create'... 'update'... 'delete'... 'options'... ]; } protected function verbs() { return [ 'index' => ['GET', 'HEAD'], 'view' =>['GET', 'HEAD'], 'create' =>['POST'], 'update' =>['PUT', 'PATCH'], 'delete' =>['DELETE'], ]; } public function checkAccess($action, $model=null, $params = []) { } }
下面來實(shí)現(xiàn)一個繼承自 這個rest\ActiveController的 News 控制器:
namespace app\controllers; use app\controllers\rest\ActiveController; #剛才這個AC,我從yii/rest下面拷貝了一份出來 class NewsController extends ActiveController { public $modelClass ='app\models\News'; }
定義到這里就足夠?qū)崿F(xiàn) rest\ActiveController 里面的默認(rèn)方法了
下面來覆蓋下,實(shí)現(xiàn)一些定制的方法
class NewsController extends ActiveController { public $modelClass = 'app\models\News'; #定制serializer #public $serializer = 'yii\rest\Serializer'; public $serializer = [ 'class' => 'app\controllers\rest\Serializer', 'collectionEnvelope' => 'items', ]; public function behaviors() { $be = ArrayHelper::merge( parent::behaviors(), [ 'verbFilter' => [ 'class' => VerbFilter::className(), 'actions' => [ 'index' => ['get'], ... ] ], 'authenticator' => [ 'class' => CompositeAuth::className(), 'authMethods' => [ HttpBasicAuth::className(), HttpBearerAuth::className(), QueryParamAuth::className(), ] ], 'contentNegotiator' => [ 'class' => ContentNegotiator::className(), 'formats' => [ 'text/html' => Response::FORMAT_HTML, ] ], 'access' => [ 'class' => AccessControl::className(), 'only' => ['view'], 'rules' => [ [ 'actions' => ['view'], 'allow' => false, 'roles' => ['@'], ], ], ] ], ); return $be; } public function checkAccess() { } }
3. 定制Actions
如果要對 Actions 進(jìn)行大的改動,建議拷貝一份出來,不要使用原始的 yii\rest\XXXAction命名空間
我這里以要實(shí)現(xiàn)對related models進(jìn)行 CURD 操作為目標(biāo)進(jìn)行大的改動
Action
在定制各個action之前, 先看看它們的基類 rest\Action, 主要是一個 findModel的方法
class Action extend \yii\base\Action { public $modelClass; public $findModel; public $checkAccess; public function init() { if($this->modelClass == null) { throw new InvalidConfigException(get_class($this). '::$modelClass must be set'); } } public function findModel($id) { if($this->findModel !== null) { return call_user_func($this->findModel, $id, $this); } $modelClass = $this->modelClass; $keys = $modelClass::primaryKey(); if(count($keys) > 1) { $values = explode(',', $id); if.. } elseif($id !== null) { $model = $modelClass::findOne($id); } if(isset($model)){ return $model; }else { throw new NotFoundHttpException("Object not found: $id"); } } }
view
view 動作不需要改動,因?yàn)?model 有 getRelated 的自有機(jī)制
class ViewAction extend Action { public function run($id) { $model = $this->findModel($id); if($this->checkAccess) { call_user_func($this->checkAccess, $this->id, $model); } } }
update
public function run($id) { /* @var $model ActiveRecord */ $model = $this->findModel($id); if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id, $model); } $model->scenario = $this->scenario; $model->load(Yii::$app->getRequest()->getBodyParams(), ''); $model->save(); return $model; }
經(jīng)過改造后,需要滿足對關(guān)聯(lián)模型的update動作
public function run($id) { /* @var $model ActiveRecord */ $model = $this->findModel($id); if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id, $model); } $model->scenario = $this->scenario; /* * * x-www-form-urlencoded key=>value * image mmmmmmmm * link nnnnnnnnnn * newsItem[title]=>ttttttttttt , don't use newsItem["title"] * newsItem[body]=>bbbbbbbbbbb * don't use newsItem=>array("title":"tttttt","body":"bbbbbbb") * don't use newsItem=>{"title":"ttttttt","body":"bbbbbbbb"} * */ $newsItem = Yii::$app->getRequest()->getBodyParams()['newsItem']; /* Array ( [title] => ttttttttttt [body] => bbbbbbbbbbb ) */ $model->newsItem->load($newsItem, ''); #$model->newsItem->load(Yii::$app->getRequest()->getBodyParams(), ''); #print_R($model->newsItem);exit; #print_R($model->newsItem);exit; if($model->save()) { $model->load(Yii::$app->getRequest()->getBodyParams(), ''); $model->newsItem->save(); } return $model; }
這里還應(yīng)該對 newsItem save 失敗 的情況進(jìn)行處理,暫且不處理。
更多關(guān)于Yii相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Yii框架入門及常用技巧總結(jié)》、《php優(yōu)秀開發(fā)框架總結(jié)》、《smarty模板入門基礎(chǔ)教程》、《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
相關(guān)文章
YII2框架中自定義用戶認(rèn)證模型,完成登陸和注冊操作示例
這篇文章主要介紹了YII2框架中自定義用戶認(rèn)證模型,完成登陸和注冊操作,結(jié)合實(shí)例形式分析了YII2通過自定義用戶認(rèn)證模型完成登陸和注冊相關(guān)操作步驟與實(shí)現(xiàn)技巧,需要的朋友可以參考下2020-03-03PHP給文字內(nèi)容中的關(guān)鍵字進(jìn)行套紅處理
本文介紹了一個PHP中的函數(shù),可以對內(nèi)容的關(guān)鍵字進(jìn)行套紅,高亮突出顯示關(guān)鍵字,分享給大家,希望對大家有所幫助。2016-04-04PHP永久登錄、記住我功能實(shí)現(xiàn)方法和安全做法
這篇文章主要介紹了PHP永久登錄、記住我功能實(shí)現(xiàn)方法和安全做法,本文著重講解用數(shù)據(jù)庫實(shí)現(xiàn)更安全的永久登錄、記住我功能,需要的朋友可以參考下2015-04-04Symfony2框架學(xué)習(xí)筆記之HTTP Cache用法詳解
這篇文章主要介紹了Symfony2框架HTTP Cache用法,結(jié)合實(shí)例形式分析了Symfony框架HTTP緩存的相關(guān)使用技巧,需要的朋友可以參考下2016-03-03