Zend_Db_Table_Selectダイナミックファインダー

こんにちは、Habr! ダイナミックファインダー



Zend_Db_Table_Selectを使用するクラスを作成し、Zend FrameworkのプロジェクトのモデルでDynamic Finderを使用できるようにしました。 このクラスで何ができるかについての記事とソースコードへのリンクが提供されています。



これは何ですか、なぜですか?





Dynamic Finderは、クラスメソッドの名前として探しているフィールドの名前と、メソッドへの引数としてこれらのフィールドの値を書き留めることにより、データベーステーブルからデータを取得できるメソッドです。 たとえば、データベーステーブルに関連付けられたモデルクラスのインスタンスで使用できます。



Dynamic Finderは、本格的なSQLクエリとサンプルを構築する形式で、モデル内にgetById(...)、getByLoginAndPassword(...)、getAllByCountry(...)の形式のメソッドを多数記述することを避けます。 代わりに、この実装では、Dynamic Finderをモデルに適切に接続するだけで十分であり、プログラマーはモデルのこれらのメソッドをコントローラーまたはビューで直接使用できます。 さらに、実際には、これらの方法はモデルにはまったく存在しません。



したがって、プログラマの時間が節約されます。



Dynamic Finderは、さまざまなライブラリやフレームワーク、特にRuby on Railsで既に何らかの形で実装されています。



この実装では、Dynamic FinderはZend_Db_Select / Zend_Db_Table_Selectを使用するアドインであり、1つのテーブルのみから選択するように設計されています。





使い方は?





いくつかのタイプの構文が使用されます。 最も単純な:

$ modelObj- > getByTag $ tag ;




getBy ...はgetAllBy ...と同じです-つまり 多くの行があるクエリを意味します。 1行のみを取得するには、getOneByを使用できます...



メソッドの名前で使用される要求フィールドの名前の構文は、キャメルケースモードでこれらのフィールドの名前を記録することです。 同時に、user_nameという形式の名前のフィールドは、メソッドの名前にUserNameとして記述する必要があります(アンダースコアで始まる各単語は大文字の単語に置き換えられます)。 「仮想メソッド」の名前の異なるフィールドは、論理演算子AndまたはOrで区切られます。



例えば

$ user- > getOneByLoginAndPassword $ login $ password ;




「仮想メソッド」の引数の構文は、2つの形式をサポートします:short(引数として、クエリの構築に使用されるフィールドのコンマ区切り値、上記の例を参照)とfull。 完全な形式では、メソッド引数として連想配列が必要であり、最も一般的な形式では次のようになります。



$ data = $ files- > getAllByPaperId

array 'values' => array $ paperId ...

'options' =>配列

'order' =>配列 'orig_filename ASC'

'offset' => $ offset

'limit' => 10

;





フィールド値(値配列、または最も単純なケース)を書き込む順序は、「仮想メソッド」の名前のフィールド名の順序に対応する必要があります。 オプションの配列とそれを含むキーと値のペアはオプションですが、デフォルト値はありません。 Zend_Db_Exprクラスのインスタンスを引数として使用することもできます。

$ data = $ tagObj- > getAllByTag new Zend_Db_Expr sprintf "LIKE ' %s %% '" $ beginStr )) ;




モデルへの接続。





私の意見では、最も簡単な方法は、モデルのDymanic Finderクラスのオブジェクトをprivate-propertyとして起動することです。

/ **

*ダイナミックファインダーオブジェクト

* @var DynamicFinder

* /

プライベート $ _dynFinder ;



パブリック 関数 __construct {

if class_exists 'DynamicFinder' false {

require_once 'path_to' '/DynamicFinder.php' ;

}



$ this- > _dynFinder = new DynamicFinder ;

}





「仮想メソッド」の一次処理。 目的のZend_Db_Table_Selectを生成した後、データベースからデータを取得します。

パブリック 関数 __call $ name $ arguments

{

$ this- > _dynFinder- > select = $ this- > getTable -> select ;

$ this- > _dynFinder- > allowedFields = $ this- > getTable -> info Zend_Db_Table_Abstract :: COLS ;



$ select = call_user_func_array array $ this- > _dynFinder $ name $ arguments ;

if strpos $ name 'getOneBy' === 0 {

return $ this- > getTable -> fetchRow $ select ;

} else {

return $ this- > getTable -> fetchAll $ select ;

}

}





$ this-> getTable()は、モデルに関連付けられたZend_Db_Tableオブジェクトを返す必要があります。



原則として、すべてが非常に異なる場合があります。 たとえば、DymanicFinderを、特定のタスクを満たすZend_Db_Table_Select(Zend_Db_Select)の事前に準備されたインスタンスに何らかの方法でselectとしてフィードできます。 また、別の方法では、テーブルで使用可能なフィールドの配列リストを渡すことができます。 同様に、Zend_Db_Select()オブジェクトの変換結果は、(getOneByをチェックするための条件の代わりに)異なる方法で処理できます。 最終的なプログラマに必要な改善のために、この場合のダイナミックファインダーは、このような「半製品」の形で作られています。 あらゆる種類のカスタマイズのため。



メソッド名の外部解析のためのオプションもあります(内部_camelCase2underscore()の代わり)。 つまり テーブルの列とフェーダーのメソッド名の命名規則は異なります。 この場合、__ callメソッドを呼び出す前のどこかで、コールバックの形式で$ this-> columnParseCallbackプロパティを定義する必要があります(call_user_func()の場合)。メソッド名の外部パーサー関数を定義します。



実装。





内部には、Zend_Db_Table_Selectの子孫(たとえば、1つのテーブルで作業する場合はZend_Db_Selectで十分です)または有効なフィールドのリストに渡さないと機能しないphpコードがあります。 しかし、仮想メソッドを作成するときに、プログラマがそれを取得するだけでは不十分ですか? ;)



クラスのソースコードはこちらから入手できます



UPD :行337のバグが修正され、フォーマットも若干修正されました。 ユーザーdmitry_dvpに感謝



All Articles