Yii2.0 初識 RESTful Serializer
當RESTful API響應中包含一個資源時,該資源需要序列化成一個字串。 Yii將這個過程分成兩步,首先,資源會被yii\rest\Serializer轉換成陣列, 然後,該陣列會通過yii\web\ResponseFormatterInterface根據請求格式(如JSON, XML)被序列化成字串。當開發一個資源類時應重點關注第一步。
所以開啟Yii框架下的vendor/yiisoft/yii2/rest/Serializer.php
public $fieldsParam = 'fields';
public $expandParam = 'expand';
public $totalCountHeader = 'X-Pagination-Total-Count';
public $pageCountHeader = 'X-Pagination-Page-Count';
public $currentPageHeader = 'X-Pagination-Current-Page';
public $perPageHeader = 'X-Pagination-Per-Page';
public $collectionEnvelope;
public $linksEnvelope = '_links';
public $metaEnvelope = '_meta';
public $request;
public $response;
變數$fieldsParam對應的是是RESTful風格中的yii\base\Model::fields()或者yii\db\ActiveRecord::fields()方法的返回值結果為一個鍵值對陣列
例如:
public function fields(){
return [
// 欄位名和屬性名相同
'id',
// 欄位名為"email", 對應的屬性名為"email_address"
'email' => 'email_address',
// 欄位名為"name", 值由一個PHP回撥函式定義
'name' => function ($model) {
return $model->first_name . ' ' . $model->last_name;
},
];}
那麼對應的當該資源被請求時返回的將是:
[
// 欄位名和屬性名相同
'id',
// 欄位名為"email", 對應的屬性名為"email_address"
'email' => 'email_address',
// 欄位名為"name", 值由一個PHP回撥函式定義
'name' => function ($model) {
return $model->first_name . ' ' . $model->last_name;
},
]
如果對應的模型層中沒有實現yii\base\Model::fields()或者yii\db\ActiveRecord::fields()方法,則會預設返回所有定義的欄位。
變數$expandParam對應的是yii\db\Model::extraFields() 和 yii\db\ActiveRecord::extraFields() 其中前者返回空值,後者返回關聯模型中定義的欄位鍵值對陣列,實現方法與yii\base\Model::fields()或者yii\db\ActiveRecord::fields()相同。
變數$totalCountHeader當請求資源時如果設定了分頁,那麼$totalCountHeader對應資源請求中的總的記錄數量。
變數$pageCountHeader當請求資源時如果設定了分頁,那麼$pageCountHeader對應資源請求中的分頁總數。
變數$currentPageHeader當請求資源時如果設定了分頁,那麼$currentPageHeader對應資源請求中的當前的頁碼。
變數$perPageHeader當請求資源時如果設定了分頁,那麼$perPageHeader對應資源請求中每一頁的記錄數量。
變數$collectionEnvelope,當發出一個資源請求,其中包括了對分頁的要求或者對於關聯操作進行的設定,那麼$collectionEnvelope就會有對應的值。
首先是返回的關聯操作,統一的是以資源請求的url形式進行返回的,宣告的時候會有譬如最典型的返回一個self連結:
class User extends ActiveRecord implements Linkable{
public function getLinks()
{
return [
Link::REL_SELF => Url::to(['user/view', 'id' => $this->id], true),
];
}
}
那麼在我們得到的資源中將會有:
{
"id": 100,
"email": "user@example.com",
// ...
"_links" => {
"self": {
"href": "https://example.com/users/100"
}
}
}
增加了一個_links標記 其中包括了我們在新增的yii\db\ActiveRecord::getLinks()中新增的url,而這個標籤內的內容恰好是變數$linksEnvelope對應的,如果設定了分頁那麼類似_links標記,還會增加一個_meta標記由$metaEnvelope對應:
'_meta' => {
// meta information as returned by Pagination::toArray() 'totalCount' => 100, 'pageCount' => 5, 'currentPage' => 1, 'perPage' => 20, }
對於變數的解釋就到這裡,接下來是對方法部分的解釋。
init()方法:
public function init()
{
if ($this->request === null) {
$this->request = Yii::$app->getRequest();
}
if ($this->response === null) {
$this->response = Yii::$app->getResponse();
}
}
每次初始化時會初始化$request和$response的值,這兩個變數的實現參考vendor/yiisoft/yii2/web/Request.php
和vendor/yiisoft/yii2/web/Respense.php 就是對資料的接收的返回的解析和封裝,這裡不做贅述。
serialize()方法:
public function serialize($data)
{
if ($data instanceof Model && $data->hasErrors()) {
return $this->serializeModelErrors($data);
} elseif ($data instanceof Arrayable) {
return $this->serializeModel($data);
} elseif ($data instanceof DataProviderInterface) {
return $this->serializeDataProvider($data);
} else {
return $data;
}
}
這一步是對資料進行序列化,將資料格式統一處理為標準的RESTful的資料格式,便於開發者操作處理。
首先看是第一個條件,判斷了$data是否為符合要求的資料,此處呼叫的yii\base\Model::hasErrors()方法的程式碼如下:
public function hasErrors($attribute = null)
{
return $attribute === null ? !empty($this->_errors) : isset($this->_errors[$attribute]);
}
當傳入資料沒有屬性,或者資料有屬性是否存在不符(通過資料層中實現的rules()方法檢驗)。
如果資料符合要求則會進入下面的序列化階段,如果傳入的資料為鍵值對那麼使用serializeModel()方法:
protected function serializeModel($model)
{
if ($this->request->getIsHead()) {
return null;
} else {
list ($fields, $expand) = $this->getRequestedFields();
return $model->toArray($fields, $expand);
}
}
首先用yii2/web/Request::getIsHead()方法來判斷當前的請求是否為HEAD請求是的話不返回資訊,如果不是則通過getRequestedFields()方法對資料進行序列化,程式碼如下:
protected function getRequestedFields()
{
$fields = $this->request->get($this->fieldsParam);
$expand = $this->request->get($this->expandParam);
return [
preg_split('/\s*,\s*/', $fields, -1, PREG_SPLIT_NO_EMPTY),
preg_split('/\s*,\s*/', $expand, -1, PREG_SPLIT_NO_EMPTY),
];
}
首先呼叫yii2/web/Request::get()方法
public function get($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getQueryParams();
} else {
return $this->getQueryParam($name, $defaultValue);
}
}public function getQueryParam($name, $defaultValue = null) { $params = $this->getQueryParams(); return isset($params[$name]) ? $params[$name] : $defaultValue; }
去掉請求中的空格並且返回非空部分作為標籤名。然後由serialize()返回該值。
如果傳入的資料型別是根據DataProviderInterface介面實現的,那麼則需要根據傳入的分頁資訊對資料進行處理。
關於Yii的Arrayable介面,詳情請見官方文件
相關文章
- Yii2.0 RESTful Web服務(3)RESTWeb
- Yii2.0 RESTful Web服務(4)RESTWeb
- Yii2.0 RESTful API 認證教程RESTAPI
- Yii2.0 RESTful API 之版本控制RESTAPI
- Yii2.0 RESTful API 之速率限制RESTAPI
- Yii2.0 RESTful API 基礎配置教程RESTAPI
- Yii2.0 RESTful風格的Controller與ActiveControllerRESTController
- Yii2.0 RESTful API 基礎配置教程[轉載]RESTAPI
- Yii2.0 實現RESTful風格的簡單APIRESTAPI
- drf Serializer基本使用
- 初識 “HTML”HTML
- 初識GolangGolang
- 初識jQueryjQuery
- Nodejs初識NodeJS
- Express初識Express
- 初識GitGit
- 初識JSJS
- CDN初識
- 初識VueVue
- webpack初識Web
- 初識HIVEHive
- 初識TcpTCP
- 初識HTTPHTTP
- 初識ARKit
- 初識HaphoopOOP
- 初識PostgreSqlSQL
- AsterixDB初識AST
- 初識Fink
- 初識WebWeb
- 初識 Shell
- 初識 reduxRedux
- 初識 SpringMVCSpringMVC
- rocketmq初識MQ
- 初識 DockerDocker
- 初識:LevelDB
- 初識JVMJVM
- 初識JavaScriptJavaScript
- 初識MybatisMyBatis