5

「車輪の再発明をしてはいけません。オープンソースのORMを使用してください」と誰かに言われたくないのです。すぐに必要なものがあり、切り替えることができません。

キャッシングをサポートする小さなORMを実行しています。キャッシュをサポートしていなくても、オブジェクトをストレージに書き込むタイミングを知るために、とにかくこの機能が必要になります。パターンはDataMapperです。

これが私のアプローチです:

  • 実行時のイントロスペクション(つまり、属性の推測)を避けたい。
  • CLIコードジェネレーターを使用してゲッターとセッターを生成したくありません(実際には、Alt + INSERTを使用してNetBeansを使用しています)。
  • モデルをPOPO(プレーンな古いPHPオブジェクト)に最も近いものにしたい。つまり、プライベート属性、各属性の「ハードコードされた」ゲッターとセッター。

AbstractModelすべてのモデルが継承するという抽象クラスがあります。isDirty()is_dirtyというプライベート(必要に応じて保護することもできます)属性で呼び出されるパブリックメソッドがあります。ロードされてからオブジェクトデータに変更があったかどうかに応じて、trueまたはfalseを返す必要があります。

問題は次のとおり"is_dirty"です。各セッターでコーディングせずに内部フラグを立てる方法はあり$this->is_dirty = trueますか?$this->attr = $valueつまり、ビジネスロジックにコードの変更が必要な場合を除いて、ほとんどの場合、セッターが必要です。

他の制限は__set、具象モデルクラスでは属性がすでにプライベートとして存在__setし、セッターで呼び出されることがないため、信頼できないことです。

何か案は?他のORMからのコード例が受け入れられます。

私のアイデアの1つは、NetBeansセッターテンプレートを変更することでしたが、IDEに依存せずにこれを行う方法があるはずだと思います。

私が持っていたもう1つの考えは、セッターを作成してから、プライベート属性の名前をアンダースコアなどで変更することでした。このように、セッターはフラグ__setを処理するために呼び出してそこにいくつかのコードを持っていますが"is_dirty"、これはPOPOの概念を少し破り、醜いです。

4

3 に答える 3

8

注意!
この件についての私の意見は、先月少し変わった。答えはまだ有効ですが、大きなオブジェクトグラフを扱う場合は、代わりに作業単位パターンを使用することをお勧めします。あなたはこの答えでそれの簡単な説明を見つけることができます

what-you-call-ModelがORMとどのように関連しているか混乱しています。ちょっと紛らわしいです。特にMVCではモデルはレイヤーであるため(少なくとも、私はそれを理解しています。あなたの「モデル」はドメインオブジェクトに似ているようです )。

私はあなたが持っているものが次のようなコードであると仮定します:

  $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には、データマッパーで使用されるデザイナーという2つのメソッドがあるgetParameters()と仮定しますsetParameters()。そして、マッパーがwhat-you-call-Modelの状態をisDirty()保存して呼び出す前に、マッパーがデータをwhat-you-call-Modelにプルするときに呼び出すこと。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単語はhas-abilities-ofを意味し、extends手段-aであるからです。

この部分まで、あなたはすでにすべてが似ているはずです...


ここで、isDirty()andcleanState()メソッドが実行する必要があることを次に示します。

  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;
  }
于 2012-06-11T23:57:57.427 に答える
1

たとえば、次のように設定するプロキシを作成します。

class BaseModel {

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

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

次に、各子クラスは呼び出しによってセッターを実装し_set()、プロパティを直接設定することはありません。さらに、いつでもより多くのクラス固有のコードを各サブクラスに挿入し、必要に応じ_setて呼び出すことparent::set($attr, $processedValue)ができます。次に、マジックメソッドを使用する場合は、にプロキシするプロパティメソッドにプロキシを作成します_set。しかし、これはあまりPOPOではないと思います。

于 2012-06-07T21:51:32.933 に答える
0

この投稿は古いですが、isDirty()が発生したときにイベントを使用してリスナーに通知するのはどうですか?私はイベントで解決策にアプローチします。

于 2013-12-18T16:56:28.130 に答える