2012-07-03 49 views
3

我們有一個基於Yii的PHP應用程序,它可以在不同類型的對象上執行一些通用操作(例如與社交網絡「共享」或在內部網上商店「購買」)。如何爲查找數據庫表定義ActiveRecord,以便它與枚舉常量一樣有用?

現在開發人員使用類常量來分離不同類型的對象。像這樣:

模式

class Referral extends CActiveRecord { 
    //... a lot more stuff here... 
    const ITEM_TYPE_PRODUCT = 'product'; 
    const ITEM_TYPE_DESIGN = 'design'; 
    const ITEM_TYPE_BRAND = 'brand'; 
    const ITEM_TYPE_INVITE = 'invite'; 
    const ITEM_TYPE_DESIGNER = 'designer'; 
    //... a lot more stuff here... 
} 

然後在一些控制器後:

// calling static method of Referral and pass a type IDs to change it's behavior 
$referral_params = Referral::buildReferallParams(
    Referral::TYPE_PINTEREST, 
    Referral::ITEM_TYPE_PRODUCT 
) 

類常量的這種使用導致我想移動的主要代碼重複遠。

我個人認爲,我們確實應該增加一個查找表類型,像這樣:

CREATE TABLE `item_type` (
    id int primary key auto_increment, 
    name varchar(255) 
); 

而且使命名ItemType從與表中提取ID的Yii的模型類。

但它會導致另一個問題:無論如何,我們需要在代碼中使用這種類型的ID,並且需要很長一段時間。我們需要以某種方式爲ID創建符號名稱。現在撥打電話Referral::ITEM_TYPE_PRODUCT非常方便,將它改爲Yii-flavoured ItemType::model()->findByAttributes(array('name' => 'Product'))是完全不能接受的。

我想避免在ItemType中維護類常量(現在通過我們的代碼庫重複)的相同列表,因爲每增加一個新類型都需要添加新的常量,而這只是一個不同步的問題等待發生。

所以,問題如下:如何使一個查詢表的ActiveRecord與'enum'-like數字常量集一樣有用?

我想出了下面的有些漂亮的解決方案,使用的ItemType類的子類:

ProductItemType::id(); // returns lazy-loaded ID for 'Product' item type 
BrandItemType::id(); // the same for 'Brand' item type 
// ... and so on 

但如果需要單獨的基類五個小類,現在,也許打的另一半更晚。有沒有可行的架構解決方案?

EDIT

問題的複製是這樣的:類常量聲明類型ID 成爲重新定義在每一個類這需要不同項目類型之間區分某種方式。我知道最「真實」的解決方案是顛倒這個內部結構,並將依賴於對象類型的特徵移動到對象本身,但是我們有遺留的代碼,沒有任何測試覆蓋,這個解決方案現在只是一個夢想。現在我想要做的就是刪除這個重複。也是常數。

+0

什麼存儲在'interface'類的所有常量,這就是我們做的,我們只是在這裏我們需要使用它們的類實現。關於第二個問題,您能否詳細說明您在代碼中重複的內容,您不想要的更多示例。 – Pentium10

+1

同意@ pentium10更清楚代碼重複。但是,如果我理解它的大部分,你的問題是如何管理你的枚舉/常量。請檢查這個[輕鬆管理常量](http://www.yiiframework.com/wiki/288/managing-constants-easily/),也許你會發現一些有用的東西。使用給定的函數,您可以將常量用作數組的任何地方(即使在驗證規則中)。 –

+0

@ Pentium10,我添加了關於代碼重複的解釋。 – hijarian

回答

1

那麼如果你想要所有這些定義一次,並從數據庫中取出。這意味着你需要做一個行爲,有類似靜態方法來檢索這些(所以常量將變成函數),你需要創建適當的魔術方法__call來覆蓋這些不存在的函數來調用你的數據庫,你可以附加這個行爲到你正在使用的任何yii類。

使用組件行爲

甲組件支持mixin圖案,並且可以與一個或幾個行爲被附接。行爲是一種對象,其方法可以通過其收集功能而不是專門化(即正常類繼承)的方式由其附加組件「繼承」。一個組件可以附加幾種行爲,從而實現「多重繼承」。

行爲類必須實現IBehavior接口。大多數行爲可以從CBehavior基類擴展而來。如果需要將行爲附加到模型上,則該行爲還可以從CModelBehaviorCActiveRecordBehavior延伸,該模型實現了爲模型指定的其他功能。

要使用行爲,必須首先通過調用行爲的attach()方法將其附加到組件。然後我們可以通過組件調用行爲方法:

// $name uniquely identifies the behavior in the component 
$component->attachBehavior($name,$behavior); 
// test() is a method of $behavior 
$component->test(); 

可以像組件的普通屬性那樣訪問附加行爲。例如,如果一個命名樹行爲被附接到一個組件,我們可以使用獲得參考此行爲對象:

$behavior=$component->tree; 
// equivalent to the following: 
// $behavior=$component->asa('tree'); 

甲行爲可以被暫時禁用,使得它的方法不是通過組件可用。例如,

$component->disableBehavior($name); 
// the following statement will throw an exception 
$component->test(); 
$component->enableBehavior($name); 
// it works now 
$component->test(); 

附加到同一組件的兩個行爲有可能具有相同名稱的方法。在這種情況下,首先附加行爲的方法將優先。

當與events一起使用時,行爲更加強大。行爲在附加到組件時,可以將其某些方法附加到組件的某些事件。通過這樣做,行爲有機會觀察或更改組件的正常執行流程。

行爲的屬性也可以通過它所連接的組件來訪問。這些屬性包括公共成員變量和通過getter和/或行爲setter定義的屬性。例如,如果行爲具有名爲xyz的屬性並且行爲被附加到組件$ a。然後我們可以使用表達式$a->xyz來訪問行爲的屬性。

更多閱讀:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.ramirezcobos.com/2010/11/19/how-to-create-a-yii-behavior/

相關問題