简介

時序模型比它聽起來的更不可怕。

通常一个資料庫實體代表資料表中的一列,當它被更新時,舊資訊会被覆寫。時序模型允許資料以時間被引用,它使得在一个所給時間查詢一个實體狀態變为可能。

例如,假設你希望追蹤產品的變更,如此當一个訂单交易成功你可以知道產品的狀態而無須重複訂单資料表中的資料。你可以让產品有時序并且使用訂单時間來引用當時下訂產品的狀態,而非它們目前的狀態,不使用時序資料的情況下就可能会是當下的狀態。

時序模型也可被用在審核變更的事物像 wiki 頁面。任何變更会被自动記錄,而不須使用一張獨立的 log 資料表。

「實體」可能是你設計中的任何項目,例如產品、使用者、多媒體文件夾、任何你会使用做为模型的可被認为是一个實體。時序模型能让你透過儲存變更,來追蹤这些實體隨著時間推移的變化,每一組新的變更被稱为一个「修訂版本」。因为每一个修訂版本與時間(時序)資料一起儲存,这使得取得一个實體在所給任何時間的狀態變为可能。

这个時序模型的實现在相同資料表儲存實體的修訂版本做为原始資料,不再需要重複的 "log" 資料表。雖然这裡的實现不是實现修訂版本的唯一方式,它是在 ORM 所給的限制之下最彈性的方式,而且事實上,它必須在多種資料庫环境下運作。

为什么在 ORM 中實现而不是選擇一个允許該功能的資料庫系统?

在 ORM 中實现時序功能能让技術被抽象出資料庫層,这能让 ORM 支援的任何資料庫使用時序模型,提供更大的靈活性。此模型不会取代使用支援時序資訊的資料庫使用能力,但提供一个「開箱即用」的實现。

使用

資料表必須被設置一个實體 ID 的複合主鍵,一个标准的自动遞增数字(例如),以及代表有效時間跨度的時間戳記。

class Model_MyTemporal extends Orm\Model_Temporal
{
	protected static $_primary_key = array('id', 'temporal_start', 'temporal_end');
	protected static $_temporal = array(
		'start_column' => 'temporal_start', // 包含此筆資料有效起始時間的行名稱
		'end_column' => 'temporal_end', // 包含此筆資料有效結束時間的行名稱
		'mysql_timestamp' => false, // 如果設为 true 将使用 MySQL 時間戳記,否則是 UNIX 時間戳記
	);
}

請注意,主鍵應該是一个實體 ID 以及時序時間戳記的複合鍵。

任何使用時序模型定義的關聯應該只涉及 ID,而不是 ID 和時間戳記。

find()

find 方法與正規模型的實现運作相同,除了只在實體最新版本,WHERE 子句被添加到 SELECT。

find_revision($id, $timestamp=null, $relations = array())

此方法可以被用來查詢實體在所給時間的狀態。

靜態
參数
參数 預設 描述
$id 必要 要搜尋實體的 ID。
$timestamp
null
要引用實體所在的時間。null 将回傳最新的修訂版本。
$relations
array
要與該實體一起載入的關聯的名稱。
回傳 单一的 Model_Temporal 子类別
範例
Model_Product::find_revision($id, '2012-11-09 12:04:00', array('images', 'reviews'));

任何透過 find_revisionfind_revisions 取回的模型應該被認为是唯讀,因为它不應該有可能修改過去!

find_revisions_between($id, $earliestTime = null, $latestTime = null)

此方法将回傳實體在所給時間之間的狀態。

靜態
參数
參数 預設 描述
$id 必要 要搜尋實體的 ID。
$earliestTime
null
要尋找最早的修訂版本時間,或 null 無限多先前的修訂版本。
$latestTime
null
字串
整数
要尋找最新的修訂版本時間,或null 無限多的修訂版本(直到最新)。
回傳 Model_Temporal 子类別的陣列
範例
Model_Product::find_revisions_between($id, '2012-11-09 12:04:00', '2012-12-10 19:00:00');

目前還不能在使用 find_revisions_between 的同時選擇關聯。

delete($cascade = null, $use_transaction = false)

此方法将從資料庫刪除物件。它與一般模型的刪除功能運作的方式完全相同,除了資訊不会從資料庫被移除。这意味著你仍然可以引用該物件在所給時間,但它就目前而言不再有效。

靜態
範例
Model_Product::find(5)->delete();

串聯刪除将正常刪除。任何不是 Soft 或 Temporal 的模型也会正常刪除。

overwrite($cascade = null, $use_transaction = false)

能让資訊被儲存而不用建立一个新的修訂版本。與 Model::save() 的運作相同。

靜態
範例
$product = Model_Product::find(5);
$product->name = 'Super Awesome 12000';
// Product 会更新而不会在資料庫中建立新的一筆資料。
$product->overwrite();

restore()

如果一个實體已经被刪除,此方法還原該實體到目前狀態。如果該實體沒有被刪除将不会发生什么事。

靜態
範例
Model_Product::find_revision(5, '2012-11-09 12:04:00')->restore();

purge()

從資料庫移除此實體的所有修訂版本。这是永久的!它不能被撤消。

靜態
範例
Model_Product::find(5)->purge();

这不能被撤消,它将從資料庫刪除實體的所有修訂版本。如果你这樣做資料将被摧毀!