問(wèn)題描述
我不希望有人說(shuō)你不應(yīng)該重新發(fā)明輪子,使用開(kāi)源 ORM";我有一個(gè)即時(shí)需求,無(wú)法切換.
我正在做一些支持緩存的 ORM.即使不支持緩存,我還是需要這個(gè)功能,以了解何時(shí)將對(duì)象寫(xiě)入存儲(chǔ).模式是 DataMapper.
這是我的方法:
- 我想避免運(yùn)行時(shí)內(nèi)省(即猜測(cè)屬性).
- 我不想使用 CLI 代碼生成器來(lái)生成 getter 和 setter(實(shí)際上我使用的是 NetBeans,使用 ALT+INSERT).
- 我希望模型最接近 POPO(普通的舊 PHP 對(duì)象).我的意思是:私有屬性,每個(gè)屬性的硬編碼"getter 和 setter.
我有一個(gè)名為 AbstractModel
的抽象類(lèi),所有模型都繼承了它.它有一個(gè)名為 isDirty()
的公共方法,帶有一個(gè)名為 is_dirty 的私有屬性(如果需要,也可以被保護(hù)).它必須返回 true 或 false,具體取決于對(duì)象數(shù)據(jù)自加載后是否發(fā)生更改.
問(wèn)題是:有沒(méi)有辦法在每個(gè) setter $this->is_dirty = true<中不用編碼就提升內(nèi)部標(biāo)志
"is_dirty"
/代碼>?我的意思是:大多數(shù)情況下,我希望將 setter 設(shè)置為 $this->attr = $value
,除非業(yè)務(wù)邏輯需要更改代碼.
其他限制是我不能依賴(lài) __set
因?yàn)樵诰唧w模型類(lèi)中屬性已經(jīng)作為私有存在,所以 __set
永遠(yuǎn)不會(huì)在 setter 上調(diào)用.>
有什么想法嗎?接受來(lái)自其他 ORM 的代碼示例.
我的一個(gè)想法是修改 NetBeans setter 模板,但我認(rèn)為應(yīng)該有一種不依賴(lài)于 IDE 的方法.
我的另一個(gè)想法是創(chuàng)建 setter,然后用下劃線(xiàn)或其他東西更改私有屬性的名稱(chēng).這樣 setter 會(huì)調(diào)用 __set
并在那里有一些代碼來(lái)處理 "is_dirty"
標(biāo)志,但這有點(diǎn)打破了 POPO 概念,而且很丑陋.
注意!
中找到對(duì)其的簡(jiǎn)要說(shuō)明
我對(duì)這個(gè)主題的看法在過(guò)去一個(gè)月有所改變.雖然答案 where 仍然有效,但在處理大型對(duì)象圖時(shí),我建議改用工作單元模式.您可以在這個(gè)答案
我有點(diǎn)困惑 what-you-call-Model 與 ORM 的關(guān)系.這有點(diǎn)令人困惑.特別是因?yàn)樵?MVC 中 Model 是一個(gè)層(至少,我是這么理解的,而你的模型"似乎更像是域?qū)ο?.
我將假設(shè)您擁有的是如下所示的代碼:
$model = new SomeModel;$mapper = $ormFactory->build('something');$model->setId(1337);$mapper->pull( $model );$model->setPayload('cogito ergo sum');$mapper->push( $model );
而且,我將假設(shè) what-you-call-Model 有兩個(gè)方法,設(shè)計(jì)器供數(shù)據(jù)映射器使用:getParameters()
和 setParameters()
.并且您在映射器存儲(chǔ) what-you-call-Model 的狀態(tài)并調(diào)用 cleanState()
之前調(diào)用 isDirty()
- 當(dāng)映射器拉數(shù)據(jù)到what-you-call-Model.
順便說(shuō)一句,如果您有更好的建議從數(shù)據(jù)映射器中獲取值而不是 setParameters()
和 getParameters()
,請(qǐng)分享,因?yàn)槲乙恢痹谂ο氤龈玫臇|西.在我看來(lái),這就像封裝泄漏.
這將使數(shù)據(jù)映射器方法看起來(lái)像:
公共函數(shù) pull( 參數(shù)化 $object ){如果 ( !$object->isDirty() ){//沒(méi)有在干凈的對(duì)象上設(shè)置任何條件//或者自上次拉取后值沒(méi)有改變返回假;//或者可能拋出異常}$data =//執(zhí)行從存儲(chǔ)中讀取信息的操作$object->setParameters($data);$object->cleanState();返回 $true;//或省略,如果替代作為例外}公共靜態(tài)函數(shù)推送(參數(shù)化 $object ){如果 ( !$object->isDirty() ){//沒(méi)有什么可以保存的,走開(kāi)返回假;//或者可能拋出異常}$data = $object->getParameters();//將值保存在存儲(chǔ)中$object->cleanState();返回 $true;//或省略,如果替代作為例外}
<塊引用>
在代碼片段中 Parametrized
是接口的名稱(chēng),該對(duì)象應(yīng)該實(shí)現(xiàn).在這種情況下,方法 getParameters()
和 setParameters()
.它有一個(gè)如此奇怪的名字,因?yàn)樵?OOP 中,implements
詞的意思是 has-abilities-of ,而 extends
表示 is-a.
到這部分為止,您應(yīng)該已經(jīng)擁有所有類(lèi)似的東西...
<小時(shí)>現(xiàn)在這里是 isDirty()
和 cleanState()
方法應(yīng)該做的:
公共函數(shù) cleanState(){$this->is_dirty = false;$temp = get_object_vars($this);取消設(shè)置( $temp['variableChecksum'] );//校驗(yàn)和不應(yīng)該是它自身的一部分$this->variableChecksum = md5( serialize( $temp ) );}公共函數(shù) isDirty(){if ( $this->is_dirty === true ){返回真;}$previous = $this->variableChecksum;$temp = get_object_vars($this);取消設(shè)置( $temp['variableChecksum'] );//校驗(yàn)和不應(yīng)該是它自身的一部分$this->variableChecksum = md5( serialize( $temp ) );返回 $previous !== $this->variableChecksum;}
I don't want anyone saying "you should not reinvent the wheel, use an open source ORM"; I have an immediate requirement and cannot switch.
I'm doing a little ORM, that supports caching. Even not supporting caching, I would need this feature anyways, to know when to write an object to storage or not. The pattern is DataMapper.
Here is my approach:
- I want to avoid runtime introspection (i.e. guessing attributes).
- I don't want to use a CLI code generator to generate getters and setters (really I use the NetBeans one, using ALT+INSERT).
- I want the model to be the closest to a POPO (plain old PHP object). I mean: private attributes, "hardcoded" getters and setters for each attribute.
I have an Abstract class called AbstractModel
that all the models inherit. It has a public method called isDirty()
with a private (can be protected too, if needed) attribute called is_dirty. It must return true or false depending if there is a change on the object data or not since it was loaded.
The issue is: is there a way to raise the internal flag "is_dirty"
without coding in each setter $this->is_dirty = true
? I mean: I want to have the setters as $this->attr = $value
most of the time, except a code change is needed for business logic.
Other limitation is that I cannot rely on __set
because on the concrete model class the attributes already exists as private, so __set
is never called on the setters.
Any ideas? Code examples from others ORMs are accepted.
One of my ideas was to modify the NetBeans setters template, but I think there should be a way of doing this without relying on the IDE.
Another thought I had was creating the setters and then change the private attribute's name with an underscore or something. This way the setter would call to __set
and have some code there to deal with the "is_dirty"
flag, but this breaks the POPO concept a little, and it's ugly.
Attention!
My opinion on the subject has somewhat changed in the past month. While the answer where is still valid, when dealing with large object graphs, I would recommend using Unit-of-Work pattern instead. You can find a brief explanation of it in this answer
I'm kinda confused how what-you-call-Model is related to ORM. It's kinda confusing. Especially since in MVC the Model is a layer (at least, thats how I understand it, and your "Models" seem to be more like Domain Objects).
I will assume that what you have is a code that looks like this:
$model = new SomeModel;
$mapper = $ormFactory->build('something');
$model->setId( 1337 );
$mapper->pull( $model );
$model->setPayload('cogito ergo sum');
$mapper->push( $model );
And, i will assume that what-you-call-Model has two methods, designer to be used by data mappers: getParameters()
and setParameters()
. And that you call isDirty()
before mapper stores what-you-call-Model's state and call cleanState()
- when mapper pull data into what-you-call-Model.
BTW, if you have a better suggestion for getting values from-and-to data mappers instead of
setParameters()
andgetParameters()
, please share, because I have been struggling to come up with something better. This seems to me like encapsulation leak.
This would make the data mapper methods look like:
public function pull( Parametrized $object )
{
if ( !$object->isDirty() )
{
// there were NO conditions set on clean object
// or the values have not changed since last pull
return false; // or maybe throw exception
}
$data = // do stuff which read information from storage
$object->setParameters( $data );
$object->cleanState();
return $true; // or leave out ,if alternative as exception
}
public static function push( Parametrized $object )
{
if ( !$object->isDirty() )
{
// there is nothing to save, go away
return false; // or maybe throw exception
}
$data = $object->getParameters();
// save values in storage
$object->cleanState();
return $true; // or leave out ,if alternative as exception
}
In the code snippet
Parametrized
is a name of interface, which object should be implementing. In this case the methodsgetParameters()
andsetParameters()
. And it has such a strange name, because in OOP, theimplements
word means has-abilities-of , while theextends
means is-a.
Up to this part you should already have everything similar...
Now here is what the isDirty()
and cleanState()
methods should do:
public function cleanState()
{
$this->is_dirty = false;
$temp = get_object_vars($this);
unset( $temp['variableChecksum'] );
// checksum should not be part of itself
$this->variableChecksum = md5( serialize( $temp ) );
}
public function isDirty()
{
if ( $this->is_dirty === true )
{
return true;
}
$previous = $this->variableChecksum;
$temp = get_object_vars($this);
unset( $temp['variableChecksum'] );
// checksum should not be part of itself
$this->variableChecksum = md5( serialize( $temp ) );
return $previous !== $this->variableChecksum;
}
這篇關(guān)于在 ORM 模型中處理臟狀態(tài)的最佳方法的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!