Issue #1206200 by plach, chx: Add support for field meta conditions in EntityFieldQuery to allow for field language updates.

8.0.x
webchick 2011-07-20 01:02:27 -07:00
parent bb6494c0d8
commit c7caef6adb
3 changed files with 273 additions and 24 deletions

View File

@ -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,

View File

@ -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().
*

View File

@ -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.
*/