今日までこれを行う必要はありませんでしたが、選択クエリに使用されているためEntityFieldQuery
、でORクエリを作成できるようには見えませんdb_or
。
例では、値がnullまたは今日以降の日付フィールドを持つすべてのエンティティを取得します。
私は何かまたは何かトリックを逃していますか、これは単にサポートされていませんか?
今日までこれを行う必要はありませんでしたが、選択クエリに使用されているためEntityFieldQuery
、でORクエリを作成できるようには見えませんdb_or
。
例では、値がnullまたは今日以降の日付フィールドを持つすべてのエンティティを取得します。
私は何かまたは何かトリックを逃していますか、これは単にサポートされていませんか?
回答:
私はこの問題の解決策を見てきました。アイデアはaddTag()
queryで使用しhook_query_TAG_alter()
、古き良きSelectQuery
オブジェクトがあるところで実装します。
EntityFieldQuery
一部のメソッドをサブラスしてオーバーライドできます。
クラスのオブジェクトに追加される条件EntityFieldQuery
(プロパティ条件など)は、配列に追加されます。
public function propertyCondition($column, $value, $operator = NULL) {
// The '!=' operator is deprecated in favour of the '<>' operator since the
// latter is ANSI SQL compatible.
if ($operator == '!=') {
$operator = '<>';
}
$this->propertyConditions[] = array(
'column' => $column,
'value' => $value,
'operator' => $operator,
);
return $this;
}
クエリが作成されると、その配列は次のようなループで使用されます(コードはEntityFieldQuery :: propertyQuery()に存在します)。
foreach ($this->propertyConditions as $property_condition) {
$this->addCondition($select_query, "$base_table." . $property_condition['column'], $property_condition);
}
$select_query
の呼び出しから返された値が含まれますdb_select()
。
恐れることはできません。ORはEntityFieldQuery
クラスによってネイティブにサポートされていません。
方法の1つは、を使用してクエリにタグを追加し、そのタグを含むクエリのクエリの内部構造を手動で変更するように->addTag()
実装hook_query_TAG_alter()
することです。
これを行うと、既存の条件をループして、OR
ロジックを追加するために必要な変更を加えることができます。しかし、それを行うためのきれいな方法ではありません。ここで例を見つけることができます。
クエリを2つに分割してマージする必要はありません。クエリを変更するだけです
シナリオを考えてみましょう:マシン名を持つ2つのエンティティタイプ:tincanステートメントとtincan_agentsがありました
エンティティ上の5つのエンティティ参照フィールド
それらの4つは通常のエンティティ参照フィールドであり、5番目(tincan_object)は複数エンティティタイプの参照フィールドです。各参照フィールドは「Agent」タイプのエンティティを参照します。
tincan_object参照フィールドは、エージェントとアクティビティ(3番目のエンティティタイプ)を参照できます。エージェントにはプロパティobject_typeがあり、これはエージェントまたはグループのいずれかです。
参照フィールドのいずれかで、いくつかの可能なエージェントの1つを参照するステートメントを見つけたいです。fieldConditionsの間にOR演算子が必要ですが、複数エンティティタイプの参照フィールドのobject_typeを確認し、2つの可能性のいずれかであることを確認する必要もあります。
以下のコードは可能な限り単純なコードを示しています。このソリューションでは、クエリには他の多くの条件、フィールドなどが含まれていたため、コードは条件の順序に依存しないようにする必要がありました。
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'tincan_statement');
$all_agents = array(4,10); //entity_ids to search for
$query->addTag('tincan_statement_get_agents');
$query->fieldCondition('tincan_actor', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
$query->fieldCondition('tincan_authority', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
$query->fieldCondition('tincan_instructor', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
$query->fieldCondition('tincan_team', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
//but then nested in the OR structure we need an AND for two columns of the multientity type reference field tincan_object
$query->fieldCondition('tincan_object', 'target_id', $all_agents, 'IN');
$query->fieldCondition('tincan_object', 'object_type', array('Agent', 'Group'), 'IN');
$results = $query->$execute();
解決策: 上記のEntityFieldQueryの注意
$query->addTag('tincan_statement_get_agents');
これはクエリにタグを付け、hook_query_TAG_alter()の実装を許可します
/**
* Implements hook_query_TAG_alter()
* alters the query for finding agents with or without the related_agents flag
* used for Statement API Get processor EntityFieldQuery
*/
function tincan_lrs_query_tincan_statement_get_agents_alter(QueryAlterableInterface $query) {
//need to or the search for all the fields (actor, object, authority, instructor, team)
// the object_type of the object field needs to be Agent OR Group
$conditions =& $query->conditions();
// dsm($conditions); //dsm() is your friend! comes with devel module
$agent_grouping_condition = db_or();
$object_parameters = array();
$x = 0;
foreach ($conditions as $key => $condition) {
if (is_numeric($key) && isset($condition['field']) && is_scalar($condition['field'])) {
if ( (strpos($condition['field'], 'tincan_object_object_type') !== FALSE ||
strpos($condition['field'], 'tincan_object_target_id') !== FALSE ) && $condition['operator'] == 'IN') {
//u
unset($conditions[$key]);
$object_parameters[$x]['field'] = $condition['field'];
$object_parameters[$x]['value'] = $condition['value'];
$object_parameters[$x]['operator'] = $condition['operator'];
$x += 1;
}
if(strpos($condition['field'], 'tincan_actor_target_id') !== FALSE ||
strpos($condition['field'], 'tincan_instructor_target_id') !== FALSE ||
strpos($condition['field'], 'tincan_team_target_id') !== FALSE ||
strpos($condition['field'], 'tincan_authority_target_id') !== FALSE ) {
unset($conditions[$key]);
$agent_grouping_condition->condition($condition['field'], $condition['value'], $condition['operator']);
}
}
}
// create new AND condition to nest in our OR condition set for the object parameters
$object_condition = db_and();
foreach($object_parameters as $key => $param) {
$object_condition->condition($param['field'], $param['value'], $param['operator']);
}
$agent_grouping_condition->condition($object_condition);
$query->condition($agent_grouping_condition);
//By default EntityFieldQuery uses inner joins, change to left
$tables =& $query->getTables();
foreach($tables as $key => $table) {
if (strpos($key, 'field_data_tincan_object') !== FALSE ||
strpos($key, 'field_data_tincan_actor') !== FALSE ||
strpos($key, 'field_data_tincan_authority') !== FALSE ||
strpos($key, 'field_data_tincan_instructor') !== FALSE ||
strpos($key, 'field_data_tincan_team') !== FALSE ) {
if(!is_null($table['join type'])) {
$tables[$key]['join type'] = 'LEFT';
}
}
}
}