最好的处理方法在ORM模型脏状态(Best way to handle dirty state in

2019-06-25 08:04发布

我不想让任何人说:“你不应该推倒重来,使用一个开源ORM”; 我有一个直接的要求,不能切换。

我做一个小的ORM,支持缓存。 即使是不支持缓存,我想反正需要这个功能,要知道什么时候一个对象写入到存储与否。 该模式是DataMapper的。

这里是我的方法:

  • 我想避免运行时内省(即猜测属性)。
  • 我不希望使用CLI代码生成器生成getter和setter(真我使用NetBeans之一,使用ALT + INSERT)。
  • 我希望模型是最接近POPO(普通旧PHP对象)。 我的意思是:为每个属性私有属性,“硬编码” getter和setter。

我有一个叫做抽象类AbstractModel所有车型继承。 它有一个叫做公共方法isDirty()与私人(可保护过,如果需要的话)的属性称为is_dirty。 如果对对象数据的变化与否,因为它加载它必须返回true或false根据。

问题是:有没有办法来提高内部标志"is_dirty"无需在每个二传手编码$this->is_dirty = true ? 我的意思是:我希望有制定机构$this->attr = $value大部分时间,除了需要对业务逻辑代码的变化。

其他限制是,我不能依靠__set ,因为在具体的模型类的属性已经存在了私人的,所以__set没有被调用的制定者。

有任何想法吗? 从别人的ORM代码示例被接受。

我的一个想法是修改NetBeans的制定者模板,但我想应该有这样做而不依赖于IDE的方式。

另一种认为我是创造的制定者,然后用下划线或东西改变私有属性的名称。 这样的setter会调用__set和有一些代码有对付"is_dirty"的标志,但是这打破了POPO概念一点点,它的丑陋。

Answer 1:

Attantion!
我关于这个问题的看法在过去的一个月中已经有所改变。 虽然这里仍然是有效的答案,与大对象图打交道时,我会建议使用单位-的-工作模式来代替。 你可以找到它的简要说明这个ansewer

我有点困惑如何什么,你呼叫模型与ORM。 它有点混乱。 特别是由于在MVC 模型是一个层(至少, 这就是我如何理解它 ,而你的“模型”在我看来,更像是域对象 )。

我会假设你拥有的是看起来像这样的代码:

  $model = new SomeModel;
  $mapper = $ormFactory->build('something');

  $model->setId( 1337 );
  $mapper->pull( $model );

  $model->setPayload('cogito ergo sum');

  $mapper->push( $model );

:而且,我会假设什么,你呼叫模型有两种方法,使用设计人员可通过数据映射器getParameters()setParameters() 而您致电isDirty()映射器前门店什么,你呼叫模式的状态,并调用cleanState() -当映射器拉入的数据是什么,您呼叫的模型

顺便说一句,如果你有获得价值更好的建议,从-和数据映射器,而不是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;
  }


Answer 2:

我会做一个代理,例如设置:

class BaseModel {

   protected function _set($attr, $value) {
      $current = $this->_get($attr);
      if($value !== $current) {
         $this->is_dirty = true;
      }

      $this->$attr = $value;
   }
}

然后,每个子类将通过调用implemnt其二传手_set()和从不直接设置属性。 此外,你可以随时注入更多的类特定代码到每个子类的_set并调用parent::set($attr, $processedValue)如果需要的话。 然后,如果你想用魔术方法来创建这些代理到代理财产法_set 。 我想这心不是很POPO虽然。



Answer 3:

虽然这个职位是旧的,但关于使用事件时isDirty()恰好通知监听器怎么样? 我会接近与事件的解决方案。



文章来源: Best way to handle dirty state in an ORM model