3

さまざまなタイプのオブジェクトに対していくつかの一般的なアクション (ソーシャル ネットワークで「共有」する、または内部 Web ショップで「購入する」など) を実行する Yii ベースの PHP アプリケーションがあります。

現在、開発者はクラス定数を使用して、異なる型のオブジェクトを分離しています。そのようです:

モデル内:

class Referral extends CActiveRecord {
    //... a lot more stuff here...
    const ITEM_TYPE_PRODUCT = 'product';
    const ITEM_TYPE_DESIGN = 'design';
    const ITEM_TYPE_BRAND = 'brand';
    const ITEM_TYPE_INVITE = 'invite';
    const ITEM_TYPE_DESIGNER = 'designer';
    //... a lot more stuff here...
}

その後、いくつかのコントローラーで:

// calling static method of Referral and pass a type IDs to change it's behavior
$referral_params = Referral::buildReferallParams(
    Referral::TYPE_PINTEREST, 
    Referral::ITEM_TYPE_PRODUCT
)

このようにクラス定数を使用すると、コードが大幅に重複するため、削除したいと考えています。

個人的には、次のようにタイプのルックアップ テーブルを追加する必要があると思います。

CREATE TABLE `item_type` (
    id int primary key auto_increment,
    name varchar(255)
);

ItemTypeそして、テーブルから ID を抽出する名前の Yii モデル クラスを作成します。

しかし、それは別の問題につながります: とにかくコード内でこの型 ID を使用する必要があり、長期間使用する必要があります。何らかの方法で ID の記号名を作成する必要があります。今のところ like の呼び出しReferral::ITEM_TYPE_PRODUCTは非常に便利であり、Yii 風に変更することItemType::model()->findByAttributes(array('name' => 'Product'))はまったく受け入れられません。

ItemType新しい型を追加するたびに新しい定数を追加する必要があり、発生するのを待っている非同期の問題であるため、クラス定数の同じリスト (現在はコードベースを通じて複製されています) を維持することは避けたいと考えています。

では、問題は次のとおりです。ルックアップ テーブルの ActiveRecord を、'enum' のような数値定数のセットと同等に役立つようにするにはどうすればよいでしょうか?

ItemType のサブクラスを使用して、次のやや美しいソリューションを作成しました。

ProductItemType::id(); // returns lazy-loaded ID for 'Product' item type
BrandItemType::id();   // the same for 'Brand' item type
// ... and so on

しかし、現在は単一の基本クラスの 5 つのサブクラスが必要であり、後でさらに 6 つ以上のサブクラスが必要になる場合があります。実行可能なアーキテクチャ上のソリューションはありますか?

編集

重複の問題は次のとおりです。タイプ ID を宣言するクラス定数は、さまざまな項目タイプを何らかの方法で区別する必要があるすべてのクラスで再定義されます。最も「真の」解決策は、これを裏返しにして、オブジェクトのタイプに依存する機能をオブジェクト自体に移動することであることは知っていますが、テストカバレッジのないレガシーコードがあり、この解決策は今のところ夢にすぎません. 今私がしたいのは、この重複を取り除くことだけです。そして定数も。

4

1 に答える 1

1

これらすべてを一度に定義し、データベースから取得する場合。つまり、動作を実行する必要があり、これらを取得するための静的なメソッドが必要です (したがって、定数は関数になります)。適切な魔法のメソッド__callを作成して、これらの存在しない関数をオーバーライドしてデータベースを呼び出す必要があり、これをアタッチできます。使用している yii クラスの動作。

コンポーネント動作の使用

コンポーネントはミックスインパターンをサポートし、1 つまたは複数の動作に関連付けることができます。ビヘイビアとは、特殊化 (つまり、通常のクラス継承) ではなく機能を収集する手段を通じて、接続されたコンポーネントによってメソッドを「継承」できるオブジェクトです。コンポーネントは複数の動作に関連付けることができるため、「多重継承」を実現できます。

動作クラスはIBehaviorインターフェイスを実装する必要があります。ほとんどの動作は、CBehavior基本クラスから拡張できます。動作をモデルに関連付ける必要がある場合は、モデル固有の追加機能を実装するCModelBehaviorまたはCActiveRecordBehaviorから拡張することもできます。

ビヘイビアを使用するには、ビヘイビアのattach()メソッドを呼び出して、最初にコンポーネントにアタッチする必要があります。次に、コンポーネントを介してビヘイビア メソッドを呼び出すことができます。

// $name uniquely identifies the behavior in the component
$component->attachBehavior($name,$behavior);
// test() is a method of $behavior
$component->test();

添付された動作は、コンポーネントの通常のプロパティのようにアクセスできます。たとえば、tree という名前の動作がコンポーネントにアタッチされている場合、次を使用してこの動作オブジェクトへの参照を取得できます。

$behavior=$component->tree;
// equivalent to the following:
// $behavior=$component->asa('tree');

コンポーネントを介してメソッドを使用できないように、動作を一時的に無効にすることができます。例えば、

$component->disableBehavior($name);
// the following statement will throw an exception
$component->test();
$component->enableBehavior($name);
// it works now
$component->test();

同じコンポーネントに関連付けられた 2 つの動作が同じ名前のメソッドを持っている可能性があります。この場合、最初にアタッチされたビヘイビアのメソッドが優先されます。

eventsと一緒に使用すると、動作はさらに強力になります。ビヘイビアは、コンポーネントにアタッチされると、そのメソッドの一部をコンポーネントのイベントにアタッチできます。そうすることで、動作はコンポーネントの通常の実行フローを観察または変更する機会を得ます。

ビヘイビアーのプロパティには、アタッチされているコンポーネントからもアクセスできます。プロパティには、パブリック メンバー変数と、動作のゲッターやセッターを介して定義されたプロパティの両方が含まれます。たとえば、動作に xyz という名前のプロパティがあり、その動作がコンポーネント $a に関連付けられているとします。次に、式$a->xyzを使用して動作のプロパティにアクセスできます。

詳細:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.ramirezcobos.com/2010/11/19/how-to-create-a-yii-behavior/

于 2012-07-05T13:34:16.380 に答える