Tidak perlu membagi kueri menjadi 2 dan menggabungkan atau semacamnya. Hanya perlu mengubah kueri
Pertimbangkan skenario: Saya memiliki 2 tipe entitas dengan nama mesin: pernyataan tincan, dan tincan_agents
5 bidang referensi entitas pada entitas
4 di antaranya adalah bidang referensi entitas reguler dan bidang ke-5 (tincan_object) adalah bidang referensi multi-entitas, setiap bidang referensi mereferensikan entitas tipe 'Agen'.
Bidang referensi tincan_object dapat merujuk Agen dan Aktivitas (tipe entitas ketiga). Agen memiliki object_type properti, yang bisa berupa Agen atau Grup.
Saya ingin menemukan Pernyataan yang merujuk salah satu dari beberapa Agen yang mungkin ada, di bidang referensi mana pun. Kami membutuhkan operator ATAU antara fieldConditions, tetapi kami juga perlu memeriksa object_type dari bidang referensi jenis multi-entitas, dan pastikan itu salah satu dari dua kemungkinan.
Kode di bawah ini mewakili yang paling sederhana yang mungkin, dalam solusi kami kueri memiliki banyak kondisi, bidang, dll ... sehingga kode yang diperlukan tidak mengandalkan urutan kondisi, atau bahkan jika semua bidang ini sedang ditanyakan.
$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();
Solusi:
Pemberitahuan di EntityFieldQuery di atas
$query->addTag('tincan_statement_get_agents');
Ini menandai kueri, memungkinkan penerapan 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';
}
}
}
}