クエリの操作

~ Query alteration 和訳 ~

ダイナミックセレクトクエリーの重要な特徴のひとつは、他のモジュールがクエリの実行時に変更を加えられることです。ノードのアクセス制限などの動作に見られるように、モジュールは自身のクエリ、もしくは他のモジュールのクエリに対しても、独自の条件の追加などを行うことができます。こういったクエリの変更機能にはタグ付けメタデータhook_query_alter() といった3つの要素があります。

タグ付け

モジュールは自身が生成するデータベースクエリに対して、特定の文字列によって「タグ付け」することが出来ます。他のモジュールはこのタグによって、フックにより変更を加えたい対象のクエリを識別します。タグに使用出来る文字列は小文字の英数字です(PHPの変数の場合と同様、使用出来るのは文字と数字とアンダースコアのみで、数字とアンダースコアは開始文字列には使えません)。クエリにタグ付けするにはaddTag()メソッドを使います。

<?php
$query->addTag('node_access');
?>

タグ付けされた操作対象のクエリを識別するには、次の3つのメソッドが使用できます。

<?php
// このタグが付いていればTRUE
$query->hasTag('example');

// これらのすべてのタグが付いていればTRUE
$query->hasAllTags('example1', 'example2');

// これらのタグのうち、いづれかが付いていればTRUE
$query->hasAnyTag('example1', 'example2');
?>

hasAllTags() と hasAnyTags() のパラメータはいくつでも指定できます。順序は関係ありません。

使用可能なタグは基本的には特に制限はありませんが、特定のタグは標準タグとして一般的に使用されます。標準化されたタグには以下のものがあります。

node_access
ノードのアクセス制限に使用されます。
translatable
This query should have translatable columns.
term_access
タクソノミータームベースのアクセス制限に使用されます。
views
Viewsモジュールによって生成されたクエリであることを示します。

メタデータ

フックで使用されることを想定したメタデータ(ノードオブジェクトなどの追加のコンテキスト)をクエリーに添付することも出来ます。メタデータは文字列をキーとして、PHPのあらゆる変数を格納できます。

<?php
$node = node_load($nid);
// ... ここで $query オブジェクトを生成したとして。
$query->addMetaData('node', $node);
?>

メタデータはそれ自体はクエリに対しての意味はなく、何の影響も及ぼしません。単にフックに対して追加的な情報を与えるためのものです。通常は特定のタグを持つ場合にのみ適用されます。

フックで対象のクエリの特定のメタデータにアクセスしたい場合は、getMetaData() を使います。

<?php
$node = $query->getMetaData('node');
?>

この場合'node'のメタデータが添付されていなければ、NULLが返されます。

hook_query_alter()

タグ付けやメタデータは、それ自体はクエリに対して何かをするものではありません。これらは単に、セレクトクエリーにおいて実際に様々な処理を追加することの出来るhook_query_alter() に対して、情報を提供するためのものです。

Drupalで実行されるダイナミックセレクトクエリーは全て、excute() メソッドの処理により、そのコンパイルの直前にhook_query_alter() を通過します。これによりモジュールは、クエリに必要な操作を加えることが可能となります。hook_query_alter() に渡される引数は1つ(クエリーオブジェクト)です。

<?php
/**
 * hook_query_alter() の実装。
 */
function example_query_alter(QueryAlterableInterface $query) {
  // ...
}
?>

特定のタグを持つクエリにのみ作用するフックももちろん用意されています。hook_query_TAG_NAME_alter() といった形になります。これの処理は汎用のフック(hook_query_alter() )がコールされた後に、セレクトクエリーに付与されたすべてのタグに対して行われます。例えば次のフックは「node_access」のタグを持つクエリにのみ作用します。

<?php
function example_query_node_access_alter(QueryAlterableInterface $query) {
  // ...
}
?>

hook_query_alter() については次の2つのポイントを押さえておく必要があります。

  1. 引数は参照渡しではありません。これは$query はオブジェクトであり、PHP 5 においてオブジェクトは重複されないということと、引数の参照渡しがここでは必ずしも必要ではないからです。オルターフックは戻り値もありません。
  2. 引数の型を「QueryAlterableInterface」と明示的に指定します。これは必ずしも必要ではありませんが、引数の型を明示的に指定することで、ランタイムに僅かながらの向上が見込めるからです。型をシンプルに「SelectQuery」とせず「QueryAlterableInterface」と指定するのは、より上位互換性を考慮してのことです。

オルターフックは、それが無限ループにつながるような、再度クエリを実行する場合を除き、特定のクエリオブジェクトに対して任意の操作を行うことが出来ます。モジュール開発者はフィールドの追加、クエリの連結、条件の追加などの操作を行うために、クエリオブジェクトの追加メソッドをコールしたり、クエリオブジェクト内部のデータ構造にアクセスして、それを直接操作することが出来ます。前者がクエリーに対して新しい情報を追加するのに適しているのに対して、後者の方法は、クエリの特定の情報を削除したり、すでにキューに入っている構造を操作することが可能です。

<?php
$fields =& $query->getFields();
$expressions =& $query->getExpressions();
$tables =& $query->getTables();
$order =& $query->getOrderBy();
$where =& $query->conditions();
$having =& $query->havingConditions();
?>

上記の全てが参照(=&)によって返される必要があることに注意してください。オルターフックは、オブジェクトと同じデータ構造にアクセスしています。上記の全てのメソッドは配列を返します。これらの一般的な構造については、SelectQuery('includes/database/select.inc')のインラインドキュメントに記載されています。

コア: 
Drupal7