我不希望任何人说“你不应该重新发明轮子,使用开源ORM”;我有立即要求,无法切换。
我正在做一些支持缓存的ORM。即使不支持缓存,我仍然需要此功能,以便知道何时将对象写入存储。模式是DataMapper。
这是我的方法:
我有一个名为AbstractModel
的抽象类,所有模型都继承。它有一个名为isDirty()
的公共方法,它带有一个名为is_dirty的私有(如果需要也可以保护)属性。它必须返回true或false,具体取决于对象数据是否有变化,因为它已被加载。
问题是:有没有办法在每个setter "is_dirty"
中无需编码的情况下引发内部标记$this->is_dirty = true
?我的意思是:我想在大多数情况下将setter设置为$this->attr = $value
,除非业务逻辑需要更改代码。
其他限制是我不能依赖__set
,因为在具体的模型类中,属性已经作为私有存在,因此永远不会在setter上调用__set
。
有什么想法吗?其他ORM的代码示例被接受。
我的一个想法是修改NetBeans setter模板,但我认为应该有一种不依赖IDE的方法。
我的另一个想法是创建setter,然后使用下划线或其他内容更改private属性的名称。这样setter就会调用__set
并在那里有一些代码来处理"is_dirty"
标志,但是这会破坏POPO概念,而且很难看。
答案 0 :(得分:8)
Attantion!
中找到它的简要说明
我对这个问题的看法在过去一个月有所改变。虽然答案仍然有效,但在处理大型对象图时,我建议使用工作单元模式。您可以在this ansewer
我很困惑你叫什么模型与ORM有关。这有点令人困惑。特别是因为在MVC中,模型是一个层(至少thats how i understand it,而你的“模型”在我看来更像Domain Objects)。
我会假设你拥有的是一个看起来像这样的代码:
$model = new SomeModel;
$mapper = $ormFactory->build('something');
$model->setId( 1337 );
$mapper->pull( $model );
$model->setPayload('cogito ergo sum');
$mapper->push( $model );
而且,我将假设 what-you-call-Model 有两种方法,设计者可供数据映射器使用:getParameters()
和setParameters()
。并且您在映射器存储调用模型的状态并调用isDirty()
之前调用cleanState()
- 当映射器将数据拉入您调用的内容时-model
BTW,如果你有更好的建议来获取数据映射器的值而不是
setParameters()
和getParameters()
,请分享,因为我一直在努力想出更好的东西。在我看来,这就像封装泄漏一样。
这会使数据映射器方法看起来像:
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
}
在代码片段
Parametrized
中是接口的名称,该对象应该实现。在这种情况下,方法getParameters()
和setParameters()
。它有一个奇怪的名字,因为在OOP中,implements
一词意味着 有能力 - ,而extends
意味着 是-A 强> 子>
到目前为止,您应该已经拥有了类似的一切......
现在,这是isDirty()
和cleanState()
方法应该做的事情:
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;
}
答案 1 :(得分:1)
我会设置一个代理来设置例如:
class BaseModel {
protected function _set($attr, $value) {
$current = $this->_get($attr);
if($value !== $current) {
$this->is_dirty = true;
}
$this->$attr = $value;
}
}
然后,每个子类都将通过调用_set()
来实现其setter,并且永远不会直接设置该属性。此外,您始终可以将更多特定于类的代码注入每个子类的_set
,并在需要时调用parent::set($attr, $processedValue)
。然后,如果要使用魔术方法,则将这些代理应用于代理_set
的属性方法。我想这不是POPO。
答案 2 :(得分:0)
虽然这篇文章很老但是当isDirty()发生时如何使用事件来通知监听器? 我会用事件来解决问题。