summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/entity.inc43
-rw-r--r--modules/field/tests/field_test.module21
-rw-r--r--modules/simpletest/tests/entity_query.test54
3 files changed, 106 insertions, 12 deletions
diff --git a/includes/entity.inc b/includes/entity.inc
index 231d36055..95e7c6b1c 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -763,14 +763,38 @@ class EntityFieldQuery {
* @endcode
*/
public function execute() {
+ // Give a chance to other modules to alter the query.
drupal_alter('entity_query', $this);
+
+ // Execute the query using the correct callback.
+ $result = call_user_func($this->queryCallback(), $this);
+
+ // Sanity checks.
+ if (!empty($this->propertyConditions)) {
+ throw new EntityFieldQueryException(t('Property query conditions were not handled in !function.', array('!function' => $function)));
+ }
+ if (!empty($this->propertyOrderBy)) {
+ throw new EntityFieldQueryException(t('Property query order by was not handled in !function.', array('!function' => $function)));
+ }
+ return $result;
+ }
+
+ /**
+ * Determines the query callback to use for this entity query.
+ *
+ * @return
+ * A callback that can be used with call_user_func().
+ */
+ public function queryCallback() {
+ // Use the override from $this->executeCallback. It can be set either
+ // while building the query, or using hook_entity_query_alter().
if (function_exists($this->executeCallback)) {
- return $this->executeCallback($this);
+ return $this->executeCallback;
}
// If there are no field conditions and sorts, and no execute callback
// then we default to querying entity tables in SQL.
if (empty($this->fields)) {
- return $this->propertyQuery();
+ return array($this, 'propertyQuery');
}
// If no override, find the storage engine to be used.
foreach ($this->fields as $field) {
@@ -781,18 +805,13 @@ class EntityFieldQuery {
throw new EntityFieldQueryException(t("Can't handle more than one field storage engine"));
}
}
- if (empty($storage)) {
- throw new EntityFieldQueryException(t("Field storage engine not found."));
- }
- $function = $storage . '_field_storage_query';
- $result = $function($this);
- if (!empty($this->propertyConditions)) {
- throw new EntityFieldQueryException(t('Property query conditions were not handled in !function.', array('!function' => $function)));
+ if ($storage) {
+ // Use hook_field_storage_query() from the field storage.
+ return $storage . '_field_storage_query';
}
- if (!empty($this->propertyOrderBy)) {
- throw new EntityFieldQueryException(t('Property query order by was not handled in !function.', array('!function' => $function)));
+ else {
+ throw new EntityFieldQueryException(t("Field storage engine not found."));
}
- return $result;
}
/**
diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module
index 9403cac76..2eac091e2 100644
--- a/modules/field/tests/field_test.module
+++ b/modules/field/tests/field_test.module
@@ -191,3 +191,24 @@ function field_test_field_delete($entity_type, $entity, $field, $instance, $item
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
+
+/**
+ * Implements hook_entity_query_alter().
+ */
+function field_test_entity_query_alter(&$query) {
+ if (!empty($query->alterMyExecuteCallbackPlease)) {
+ $query->executeCallback = 'field_test_dummy_field_storage_query';
+ }
+}
+
+/**
+ * Pseudo-implements hook_field_storage_query().
+ */
+function field_test_dummy_field_storage_query(EntityFieldQuery $query) {
+ // Return dummy values that will be checked by the test.
+ return array(
+ 'user' => array(
+ 1 => entity_create_stub_entity('user', array(1, NULL, NULL)),
+ ),
+ );
+}
diff --git a/modules/simpletest/tests/entity_query.test b/modules/simpletest/tests/entity_query.test
index aa1beef4f..b765d03d2 100644
--- a/modules/simpletest/tests/entity_query.test
+++ b/modules/simpletest/tests/entity_query.test
@@ -819,6 +819,60 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
}
/**
+ * Tests the routing feature of EntityFieldQuery.
+ */
+ function testEntityFieldQueryRouting() {
+ // Entity-only query.
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'test_entity_bundle_key');
+ $this->assertIdentical($query->queryCallback(), array($query, 'propertyQuery'), t('Entity-only queries are handled by the propertyQuery handler.'));
+
+ // Field-only query.
+ $query = new EntityFieldQuery();
+ $query->fieldCondition($this->fields[0], 'value', '3');
+ $this->assertIdentical($query->queryCallback(), 'field_sql_storage_field_storage_query', t('Pure field queries are handled by the Field storage handler.'));
+
+ // Mixed entity and field query.
+ $query = new EntityFieldQuery();
+ $query
+ ->entityCondition('entity_type', 'test_entity_bundle_key')
+ ->fieldCondition($this->fields[0], 'value', '3');
+ $this->assertIdentical($query->queryCallback(), 'field_sql_storage_field_storage_query', t('Mixed queries are handled by the Field storage handler.'));
+
+ // Overriding with $query->executeCallback.
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'test_entity_bundle_key');
+ $query->executeCallback = 'field_test_dummy_field_storage_query';
+ $this->assertEntityFieldQuery($query, array(
+ array('user', 1),
+ ), t('executeCallback can override the query handler.'));
+
+ // Overriding with $query->executeCallback via hook_entity_query_alter().
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'test_entity_bundle_key');
+ // Add a flag that will be caught by field_test_entity_query_alter().
+ $query->alterMyExecuteCallbackPlease = TRUE;
+ $this->assertEntityFieldQuery($query, array(
+ array('user', 1),
+ ), t('executeCallback can override the query handler when set in a hook_entity_query_alter().'));
+
+ // Mixed-storage queries.
+ $query = new EntityFieldQuery();
+ $query
+ ->fieldCondition($this->fields[0], 'value', '3')
+ ->fieldCondition($this->fields[1], 'shape', 'squ', 'STARTS_WITH');
+ // Alter the storage of the field.
+ $query->fields[1]['storage']['module'] = 'dummy_storage';
+ try {
+ $query->queryCallback();
+ }
+ catch (EntityFieldQueryException $exception) {
+ $pass = ($exception->getMessage() == t("Can't handle more than one field storage engine"));
+ }
+ $this->assertTrue($pass, t('Cannot query across field storage engines.'));
+ }
+
+ /**
* Fetches the results of an EntityFieldQuery and compares.
*
* @param $query