在今天之前,我从未需要执行此操作,但是您似乎不能使用进行OR查询EntityFieldQuery
,因为db_or
它用于选择查询。
一个示例将涉及具有日期字段(该字段的值为空或今天之后)的所有实体。
我是否缺少某些东西或技巧,或者根本不支持此方法?
在今天之前,我从未需要执行此操作,但是您似乎不能使用进行OR查询EntityFieldQuery
,因为db_or
它用于选择查询。
一个示例将涉及具有日期字段(该字段的值为空或今天之后)的所有实体。
我是否缺少某些东西或技巧,或者根本不支持此方法?
Answers:
您可以细分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()
。
您不必担心,EntityFieldQuery
该类本身不支持OR 。
绕过它的一种方法可能是使用,将标签添加到查询中->addTag()
,然后实施hook_query_TAG_alter()
以针对包含该标签的查询手动更改查询的内部结构。
无需将查询分为2个并合并或类似的东西。只需更改查询
考虑这种情况:我有两种带有机器名称的实体类型:tincan语句和tincan_agents
实体上的5个实体参考字段
其中的4个是常规实体参考字段,第5个(tincan_object)是一个多实体类型参考字段,每个参考字段都参考一个类型为“代理”的实体。
tincan_object参考字段可以参考代理和活动(第三种实体类型)。代理具有属性object_type,可以是代理或组。
我想在任何参考字段中找到任何引用几个可能的代理之一的语句。我们在fieldConditions之间需要一个OR运算符,但是我们还需要检查多实体类型引用字段的object_type,并确保它是两种可能性之一。
下面的代码代表了最简单的方法,在我们的解决方案中,查询中还有许多其他条件,字段等...,因此该代码无需考虑条件的顺序,甚至不必查询所有这些字段。
$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';
}
}
}
}