虛擬表和視圖
表ApiLog中有一個字段叫app,表示前端應用名:
@ApiLog: id, tm, addr, app, userId
- userId: 如果app=user,則關聯到User表;如果app=emp,則關聯到員工表Employee
@Employee: id, name, phone, ...
@User: id, ...
當app=”emp”時,就表示是員工端應用的操作日誌。
現在想對員工端操作日誌進行查詢,定義以下接口:
EmpLog.query() -> tbl(id, tm, userId, ac, ..., empName?, empPhone?)
返回
- empName/empPhone: 關聯字段,通過userId關聯到Employee表的name/phone字段。
應用邏輯
- 權限:AUTH_EMP
EmpLog是一個虛擬對象或虛擬表,實現時,一種辦法是可以在數據庫定義一個視圖,如:
CREATE VIEW EmpLog AS
SELECT t0.id, tm, userId, ac, e.name empName, e.phone empPhone
FROM ApiLog t0
LEFT JOIN Employee e ON e.id=t0.userId
WHERE t0.app='emp' AND t0.userId IS NOT NULL
ORDER BY t0.id DESC
然後可將該視圖當作表一樣查詢(但不可更新),如:
class AC2_EmpLog extends AccessControl
{
protected $allowedAc = ["query"];
}
這樣就可以實現上述接口了。
另一種辦法是直接使用AccessControl創建虛擬表,代碼如下:
class AC2_EmpLog extends AccessControl
{
protected $allowedAc = ["query"];
protected $table = 'ApiLog';
protected $defaultSort = "t0.id DESC";
protected $defaultRes = "id, tm, userId, ac, req, res, reqsz, ressz, empName, empPhone";
protected $vcolDefs = [
[
"res" => ["e.name AS empName", "e.phone AS empPhone"],
"join" => "LEFT JOIN Employee e ON e.id=t0.userId"
]
];
// get/query操作都會走這裏
protected function onQuery() {
$this->addCond("t0.app='emp' and t0.userId IS NOT NULL");
}
}
與上例相比,它不僅無須在數據庫中創建視圖,還也可以進行更新。
其要點是:
- 重寫
$table
屬性, 定義實際表 - 用屬性
$vcolDefs
定義虛擬字段 - 用addCond方法添加缺省查詢條件
屬性$defaultSort
和$defaultRes
可用於定義缺省返回字段及排序方式。
在get/query接口中可以用”res”指定返回字段,如果未指定,則會返回除了$hiddenFields定義的字段之外,所有主表中的字段,還會包括設置了default=>true
的虛擬字段。
通過$defaultRes
可以指定缺省返回字段列表。
query接口中可以通過”orderby”來指定排序方式,如果未指定,默認是按id排序的,通過$defaultSort
可以修改默認排序方式。