오늘 전에이 작업을 수행 할 필요가 없었지만 select 쿼리에 사용 EntityFieldQuery
되기 때문에 OR 쿼리를 수행 할 수있는 것처럼 보이지 않습니다 db_or
.
예를 들어 값이 null이거나 오늘 이후 인 날짜 필드가있는 모든 엔티티에 도달합니다.
무언가 또는 일부 트릭이 누락되었거나 단순히 지원되지 않습니까?
오늘 전에이 작업을 수행 할 필요가 없었지만 select 쿼리에 사용 EntityFieldQuery
되기 때문에 OR 쿼리를 수행 할 수있는 것처럼 보이지 않습니다 db_or
.
예를 들어 값이 null이거나 오늘 이후 인 날짜 필드가있는 모든 엔티티에 도달합니다.
무언가 또는 일부 트릭이 누락되었거나 단순히 지원되지 않습니까?
답변:
나는 이 문제 의 해결책을 보았다 . 좋은 오래된 객체 가 addTag()
있는 query and implement 에 사용하는 것이 좋습니다 .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
수업에서 기본적으로 지원되지 않습니다 .
한 가지 방법은 with로 쿼리에 태그를 추가 한 ->addTag()
다음 hook_query_TAG_alter()
해당 태그가 포함 된 쿼리에 대해 쿼리의 내부 구조를 수동으로 변경하도록 구현 하는 것입니다.
이렇게하면 기존 조건을 반복하고 OR
논리 를 추가하기 위해 필요한 변경을 수행 할 수 있습니다 . 하지만 그렇게하는 것은 좋은 방법이 아닙니다. 여기서 예 를 찾을 수 있습니다 .
쿼리를 2로 나누고 병합하는 등의 작업이 필요 없습니다. 검색어를 변경하면됩니다.
시나리오를 고려하십시오 : 나는 기계 이름을 가진 2 개의 엔티티 유형을 가지고 있습니다 : tincan 문과 tincan_agents
엔티티의 5 개의 엔티티 참조 필드
그 중 4 개는 일반 엔티티 참조 필드이고 5 번째 (tincan_object)는 다중 엔티티 유형 참조 필드이며 각 참조 필드는 'Agent'유형의 엔티티를 참조합니다.
tincan_object 참조 필드는 에이전트 및 활동 (제 3 엔티티 유형)을 참조 할 수 있습니다. 에이전트는 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';
}
}
}
}