在ORM模型中处理脏状态的最佳方法

Die*_*ego 5 php oop model-view-controller orm

我不希望任何人说"你不应该重新发明轮子,使用开源ORM" ; 我有一个立即的要求,不能切换.

我正在做一些支持缓存的ORM.即使不支持缓存,我仍然需要此功能,以便知道何时将对象写入存储.模式是DataMapper.

这是我的方法:

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

我有一个名为AbstractModel所有模型继承的抽象类.它有一个isDirty()名为is_dirty的私有(也可以保护,如果需要)的属性调用的公共方法.它必须返回true或false,具体取决于对象数据是否有更改,因为它已加载.

问题是:有没有办法"is_dirty"在每个setter中编译内部标志而不编码$this->is_dirty = true?我的意思是:$this->attr = $value除了业务逻辑需要更改代码之外,我希望大多数时间都有setter .

其他限制是我不能依赖,__set因为在具体的模型类中,属性已经作为私有存在,因此__set永远不会在setter上调用.

有任何想法吗?其他ORM的代码示例被接受.

我的一个想法是修改NetBeans setters模板,但我认为应该有一种方法可以在不依赖IDE的情况下执行此操作.

我的另一个想法是创建setter,然后用下划线或其他东西更改private属性的名称.这样setter会调用__set并在那里处理一些代码来处理"is_dirty"标志,但是这会破坏POPO概念,而且很难看.

ter*_*ško 8

Attantion!
我对这个问题的看法在过去一个月有所改变.虽然答案仍然有效,但在处理大型对象图时,我建议使用工作单元模式.你可以在这个问题中找到它的简要说明

我有点困惑你怎么称呼模型与ORM有关.这有点令人困惑.特别是因为在MVC中,模型是一个层(至少,这就是我理解它,你的"模型"在我看来更像是 Domain Objects).

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

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

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

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

  $mapper->push( $model );
Run Code Online (Sandbox Code Playgroud)

并且,我将假设你所谓的模型有两种方法,设计者可供数据映射器使用:getParameters()setParameters().并且你isDirty()在mapper存储之前调用你调用的模型的状态和调用cleanState()- 当mapper将数据拉入你调用的模型时.

顺便说一句,如果你有更好的建议从数据映射器获取值而不是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
  }
Run Code Online (Sandbox Code Playgroud)

在代码片段中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;
  }
Run Code Online (Sandbox Code Playgroud)