Keine Notwendigkeit, Abfragen in 2 zu teilen und zusammenzuführen oder ähnliches. Müssen nur die Abfrage ändern
Stellen Sie sich das Szenario vor: Ich hatte zwei Entitätstypen mit Maschinennamen: tincan-Anweisungen und tincan_agents
5 Entitätsreferenzfelder auf der Entität
4 davon sind reguläre Entitätsreferenzfelder und das fünfte (tincan_object) ist ein Referenzfeld mit mehreren Entitäten, wobei jedes Referenzfeld auf Entitäten vom Typ 'Agent' verweist.
Das Referenzfeld tincan_object kann auf Agenten und Aktivitäten verweisen (ein dritter Entitätstyp). Ein Agent hat eine Eigenschaft object_type, die entweder Agent oder Group sein kann.
Ich möchte eine Aussage finden, die auf einen von mehreren möglichen Agenten in einem der Referenzfelder verweist. Wir benötigen einen OR-Operator zwischen den fieldConditions, müssen aber auch den object_type des Referenzfelds mit mehreren Entitätstypen überprüfen und sicherstellen, dass es sich um eine von zwei Möglichkeiten handelt.
Der folgende Code stellt den einfachsten möglichen Code dar. In unserer Lösung hatte die Abfrage viele andere Bedingungen, Felder usw., sodass der Code nicht mit der Reihenfolge der Bedingungen gerechnet werden musste oder auch wenn alle diese Felder abgefragt wurden.
$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();
Lösung:
Beachten Sie in der obigen EntityFieldQuery
$query->addTag('tincan_statement_get_agents');
Dies markiert die Abfrage und ermöglicht die Implementierung von 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';
}
}
}
}