Issue #1206200 by plach, chx: Add support for field meta conditions in EntityFieldQuery to allow for field language updates.
parent
bb6494c0d8
commit
c7caef6adb
|
@ -457,6 +457,21 @@ class EntityFieldQuery {
|
|||
*/
|
||||
public $fieldConditions = array();
|
||||
|
||||
/**
|
||||
* List of field meta conditions (language and delta).
|
||||
*
|
||||
* Field conditions operate on columns specified by hook_field_schema(),
|
||||
* the meta conditions operate on columns added by the system: delta
|
||||
* and language. These can not be mixed with the field conditions because
|
||||
* field columns can have any name including delta and language.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see EntityFieldQuery::fieldLanguageCondition()
|
||||
* @see EntityFieldQuery::fielDeltaCondition()
|
||||
*/
|
||||
public $fieldMetaConditions = array();
|
||||
|
||||
/**
|
||||
* List of property conditions.
|
||||
*
|
||||
|
@ -613,6 +628,90 @@ class EntityFieldQuery {
|
|||
/**
|
||||
* Adds a condition on field values.
|
||||
*
|
||||
* @param $type
|
||||
* The condition array the given conditions should be added to.
|
||||
* @param $field
|
||||
* Either a field name or a field array.
|
||||
* @param $column
|
||||
* The column that should hold the value to be matched.
|
||||
* @param $value
|
||||
* The value to test the column value against.
|
||||
* @param $operator
|
||||
* The operator to be used to test the given value.
|
||||
* @param $delta_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $delta_group.
|
||||
* @param $language_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $language_group.
|
||||
*
|
||||
* @return EntityFieldQuery
|
||||
* The called object.
|
||||
*
|
||||
* @see EntityFieldQuery::addFieldCondition
|
||||
* @see EntityFieldQuery::deleted
|
||||
*/
|
||||
public function fieldCondition($field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) {
|
||||
return $this->addFieldCondition($this->fieldConditions, $field, $column, $value, $operator, $delta_group, $language_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition on the field language column.
|
||||
*
|
||||
* @param $field
|
||||
* Either a field name or a field array.
|
||||
* @param $value
|
||||
* The value to test the column value against.
|
||||
* @param $operator
|
||||
* The operator to be used to test the given value.
|
||||
* @param $delta_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $delta_group.
|
||||
* @param $language_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $language_group.
|
||||
*
|
||||
* @return EntityFieldQuery
|
||||
* The called object.
|
||||
*
|
||||
* @see EntityFieldQuery::addFieldCondition
|
||||
* @see EntityFieldQuery::deleted
|
||||
*/
|
||||
public function fieldLanguageCondition($field, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) {
|
||||
return $this->addFieldCondition($this->fieldMetaConditions, $field, 'language', $value, $operator, $delta_group, $language_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition on the field delta column.
|
||||
*
|
||||
* @param $field
|
||||
* Either a field name or a field array.
|
||||
* @param $value
|
||||
* The value to test the column value against.
|
||||
* @param $operator
|
||||
* The operator to be used to test the given value.
|
||||
* @param $delta_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $delta_group.
|
||||
* @param $language_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $language_group.
|
||||
*
|
||||
* @return EntityFieldQuery
|
||||
* The called object.
|
||||
*
|
||||
* @see EntityFieldQuery::addFieldCondition
|
||||
* @see EntityFieldQuery::deleted
|
||||
*/
|
||||
public function fieldDeltaCondition($field, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) {
|
||||
return $this->addFieldCondition($this->fieldMetaConditions, $field, 'delta', $value, $operator, $delta_group, $language_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given condition to the proper condition array.
|
||||
*
|
||||
* @param $conditions
|
||||
* A reference to an array of conditions.
|
||||
* @param $field
|
||||
* Either a field name or a field array.
|
||||
* @param $column
|
||||
|
@ -649,7 +748,7 @@ class EntityFieldQuery {
|
|||
* @return EntityFieldQuery
|
||||
* The called object.
|
||||
*/
|
||||
public function fieldCondition($field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) {
|
||||
protected function addFieldCondition(&$conditions, $field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) {
|
||||
if (is_scalar($field)) {
|
||||
$field_definition = field_info_field($field);
|
||||
if (empty($field_definition)) {
|
||||
|
@ -657,11 +756,11 @@ class EntityFieldQuery {
|
|||
}
|
||||
$field = $field_definition;
|
||||
}
|
||||
// Ensure the same index is used for fieldConditions as for fields.
|
||||
// Ensure the same index is used for field conditions as for fields.
|
||||
$index = count($this->fields);
|
||||
$this->fields[$index] = $field;
|
||||
if (isset($column)) {
|
||||
$this->fieldConditions[$index] = array(
|
||||
$conditions[$index] = array(
|
||||
'field' => $field,
|
||||
'column' => $column,
|
||||
'value' => $value,
|
||||
|
|
|
@ -468,7 +468,6 @@ function field_sql_storage_field_storage_purge($entity_type, $entity, $field, $i
|
|||
* Implements hook_field_storage_query().
|
||||
*/
|
||||
function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
|
||||
$groups = array();
|
||||
if ($query->age == FIELD_LOAD_CURRENT) {
|
||||
$tablename_function = '_field_sql_storage_tablename';
|
||||
$id_key = 'entity_id';
|
||||
|
@ -499,26 +498,12 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
|
|||
}
|
||||
}
|
||||
|
||||
// Add field conditions.
|
||||
foreach ($query->fieldConditions as $key => $condition) {
|
||||
$table_alias = $table_aliases[$key];
|
||||
$field = $condition['field'];
|
||||
// Add the specified condition.
|
||||
$sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $condition['column']);
|
||||
$query->addCondition($select_query, $sql_field, $condition);
|
||||
// Add delta / language group conditions.
|
||||
foreach (array('delta', 'language') as $column) {
|
||||
if (isset($condition[$column . '_group'])) {
|
||||
$group_name = $condition[$column . '_group'];
|
||||
if (!isset($groups[$column][$group_name])) {
|
||||
$groups[$column][$group_name] = $table_alias;
|
||||
}
|
||||
else {
|
||||
$select_query->where("$table_alias.$column = " . $groups[$column][$group_name] . ".$column");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add field conditions. We need a fresh grouping cache.
|
||||
drupal_static_reset('_field_sql_storage_query_field_conditions');
|
||||
_field_sql_storage_query_field_conditions($query, $select_query, $query->fieldConditions, $table_aliases, '_field_sql_storage_columnname');
|
||||
|
||||
// Add field meta conditions.
|
||||
_field_sql_storage_query_field_conditions($query, $select_query, $query->fieldMetaConditions, $table_aliases, function ($field_name, $column) { return $column; });
|
||||
|
||||
if (isset($query->deleted)) {
|
||||
$select_query->condition("$field_base_table.deleted", (int) $query->deleted);
|
||||
|
@ -591,6 +576,44 @@ function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity
|
|||
return $entity_base_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds field (meta) conditions to the given query objects respecting groupings.
|
||||
*
|
||||
* @param EntityFieldQuery $query
|
||||
* The field query object to be processed.
|
||||
* @param SelectQuery $select_query
|
||||
* The SelectQuery that should get grouping conditions.
|
||||
* @param condtions
|
||||
* The conditions to be added.
|
||||
* @param $table_aliases
|
||||
* An associative array of table aliases keyed by field index.
|
||||
* @param $column_callback
|
||||
* A callback that should return the column name to be used for the field
|
||||
* conditions. Accepts a field name and a field column name as parameters.
|
||||
*/
|
||||
function _field_sql_storage_query_field_conditions(EntityFieldQuery $query, SelectQuery $select_query, $conditions, $table_aliases, $column_callback) {
|
||||
$groups = &drupal_static(__FUNCTION__, array());
|
||||
foreach ($conditions as $key => $condition) {
|
||||
$table_alias = $table_aliases[$key];
|
||||
$field = $condition['field'];
|
||||
// Add the specified condition.
|
||||
$sql_field = "$table_alias." . $column_callback($field['field_name'], $condition['column']);
|
||||
$query->addCondition($select_query, $sql_field, $condition);
|
||||
// Add delta / language group conditions.
|
||||
foreach (array('delta', 'language') as $column) {
|
||||
if (isset($condition[$column . '_group'])) {
|
||||
$group_name = $condition[$column . '_group'];
|
||||
if (!isset($groups[$column][$group_name])) {
|
||||
$groups[$column][$group_name] = $table_alias;
|
||||
}
|
||||
else {
|
||||
$select_query->where("$table_alias.$column = " . $groups[$column][$group_name] . ".$column");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_storage_delete_revision().
|
||||
*
|
||||
|
|
|
@ -1049,6 +1049,133 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
|
|||
$this->assertTrue($pass, t("Can't query the universe."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests field meta conditions.
|
||||
*/
|
||||
function testEntityFieldQueryMetaConditions() {
|
||||
// Make a test field translatable.
|
||||
$this->fields[0]['translatable'] = TRUE;
|
||||
field_update_field($this->fields[0]);
|
||||
field_test_entity_info_translatable('test_entity', TRUE);
|
||||
drupal_static_reset('field_available_languages');
|
||||
|
||||
// Create more items with different languages.
|
||||
$entity = new stdClass();
|
||||
$entity->ftid = 1;
|
||||
$entity->ftvid = 1;
|
||||
$entity->fttype = 'test_bundle';
|
||||
$j = 0;
|
||||
|
||||
foreach (array(LANGUAGE_NONE, 'en') as $langcode) {
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$entity->{$this->field_names[0]}[$langcode][$i]['value'] = $i + $j;
|
||||
}
|
||||
$j += 4;
|
||||
}
|
||||
|
||||
field_attach_update('test_entity', $entity);
|
||||
|
||||
// Test delta field meta condition.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldDeltaCondition($this->fields[0], 0, '>');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity', 1),
|
||||
), t('Test with a delta meta condition.'));
|
||||
|
||||
// Test language field meta condition.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity', 1),
|
||||
), t('Test with a language meta condition.'));
|
||||
|
||||
// Test delta grouping.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'group')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '<', 'group');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity', 1),
|
||||
), t('Test with a grouped delta meta condition.'));
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'group')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '>=', 'group');
|
||||
$this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta meta condition (empty result set).'));
|
||||
|
||||
// Test language grouping.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', NULL, 'group')
|
||||
->fieldLanguageCondition($this->fields[0], 'en', '!=', NULL, 'group');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity', 1),
|
||||
), t('Test with a grouped language meta condition.'));
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', NULL, 'group')
|
||||
->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', NULL, 'group');
|
||||
$this->assertEntityFieldQuery($query, array(), t('Test with a grouped language meta condition (empty result set).'));
|
||||
|
||||
// Test delta and language grouping.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '<', 'delta', 'language')
|
||||
->fieldLanguageCondition($this->fields[0], 'en', '!=', 'delta', 'language');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity', 1),
|
||||
), t('Test with a grouped delta + language meta condition.'));
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '>=', 'delta', 'language')
|
||||
->fieldLanguageCondition($this->fields[0], 'en', '!=', 'delta', 'language');
|
||||
$this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, delta condition unsatisifed).'));
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '<', 'delta', 'language')
|
||||
->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', 'delta', 'language');
|
||||
$this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, language condition unsatisifed).'));
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity', '=')
|
||||
->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language')
|
||||
->fieldDeltaCondition($this->fields[0], 1, '>=', 'delta', 'language')
|
||||
->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', 'delta', 'language');
|
||||
$this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, both conditions unsatisifed).'));
|
||||
|
||||
// Test grouping with another field to ensure that grouping cache is reset
|
||||
// properly.
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity_bundle', '=')
|
||||
->fieldCondition($this->fields[1], 'shape', 'circle', '=', 'delta', 'language')
|
||||
->fieldCondition($this->fields[1], 'color', 'blue', '=', 'delta', 'language')
|
||||
->fieldDeltaCondition($this->fields[1], 1, '=', 'delta', 'language')
|
||||
->fieldLanguageCondition($this->fields[1], LANGUAGE_NONE, '=', 'delta', 'language');
|
||||
$this->assertEntityFieldQuery($query, array(
|
||||
array('test_entity_bundle', 5),
|
||||
), t('Test grouping cache.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the routing feature of EntityFieldQuery.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue