summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/entity.inc105
-rw-r--r--modules/field/modules/field_sql_storage/field_sql_storage.module65
-rw-r--r--modules/simpletest/tests/entity_query.test127
3 files changed, 273 insertions, 24 deletions
diff --git a/includes/entity.inc b/includes/entity.inc
index 9ee7889cf..f363c3113 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -458,6 +458,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.
*
* @var array
@@ -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,
diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module b/modules/field/modules/field_sql_storage/field_sql_storage.module
index 6f49167ec..89aeca66f 100644
--- a/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -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);
@@ -592,6 +577,44 @@ function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity
}
/**
+ * 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().
*
* This function actually deletes the data from the database.
diff --git a/modules/simpletest/tests/entity_query.test b/modules/simpletest/tests/entity_query.test
index d28d5a35c..0fe8106ef 100644
--- a/modules/simpletest/tests/entity_query.test
+++ b/modules/simpletest/tests/entity_query.test
@@ -1050,6 +1050,133 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
}
/**
+ * 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.
*/
function testEntityFieldQueryRouting() {