Drupal 7 でのデータベース操作 - レッスン 5 - エクステンダー
Drupal の SELECT クエリは エクステンダー をサポートします。エクステンダーを使うと、実行時に SELECT クエリに機能を追加できます。この機能は、新しいメソッドである場合も、既存のメソッドの動作を上書きする場合もあります。
これはオブジェクト指向プログラミングのデザインパターンを使って実現されます。エクステンダーは Decorator パターン を実装しており、クエリメソッドの柔軟なサブクラスのような拡張を提供することで、動的なオブジェクトに追加の責務を付与します。
エクステンダーの使用
エクステンダーを使うには、クエリオブジェクトから始める必要があります。クエリに対して extend() メソッドを呼び出すと、機能が追加された新しいオブジェクトが返されます。たとえば:
extend('PagerDefault');
?>
この例では、新しい PagerDefault オブジェクトが元のクエリオブジェクトをラップし、ページネーション機能を追加します。$query 変数は返された拡張オブジェクトに置き換えられます――これは拡張メソッドを使う上で重要です。extend() の結果を代入し忘れると、拡張機能へのアクセスを失います:
fields('n', array('nid', 'title'))
->extend('PagerDefault') // returns a new object
->limit(5); // works on the PagerDefault object
// But this refers to the original SelectQuery object again!
$query->orderBy('title');
// So the execute() below won't use the PagerDefault features.
$result = $query->execute();
?>
こうした問題を避けるため、常に extend() の結果をクエリ変数に代入し直してください:
extend('PagerDefault')->extend('TableSort');
$query->fields(...);
// ...
?>
これにより、メソッドを呼び出す前に $query が完全に拡張されていることが保証されます。複数のエクステンダーをチェーンできますが、順序が重要になり得ることに注意してください。たとえば、TableSort は PagerDefault の後に来るべきです。
カスタムエクステンダーの作成
エクステンダーは、単に SelectQueryInterface を実装し、コンストラクターで 2 つのパラメーター(ベースの select クエリとデータベース接続)を受け取るクラスです。通常は、インターフェースのほとんどを処理してくれる SelectQueryExtender をサブクラス化します。
SelectQueryExtender をサブクラス化することで、任意のエクステンダーを定義できます。クラスの名前が extend() に渡すものです。必要に応じて、既存のメソッドを上書きしたり、独自のメソッドを定義したりできます。
エクステンダーは、インターフェースが期待するもの――通常はクエリオブジェクトまたは別のエクステンダーオブジェクト――を返さなければなりません。メソッドをチェーンしたり、好きなようにクエリを装飾したりできます。
エクステンダーの例
query->orderBy($field, $direction);
return $this;
}
}
?>
この例では、orderBy() が何もしない処理で上書きされ、実際のソートを行う新しいメソッド orderByForReal() が導入されています。どちらのメソッドも、チェーンのためにクエリオブジェクトを保持するよう $this を返します。
どのモジュールも独自のエクステンダーを定義できます。Drupal コアは、2 つの便利な組み込みエクステンダー PagerDefault と TableSort を提供しています。
複数のデータベースのサポート
db_select() と同様に、エクステンダーもデータベース固有のバージョンをサポートします。Drupal は自動的に、あなたのエクステンダークラスのデータベース固有のサフィックスを探します。たとえば:
ExampleExtender_pgsqlExampleExtender_mysql
利用可能な場合、Drupal は DBMS 固有のクラスを自動的に使います。これにより、クエリ処理で一貫したロジックを維持しつつ、異なるデータベースバックエンドとの互換性を確保できます。