diff options
-rw-r--r-- | includes/entity.inc | 43 | ||||
-rw-r--r-- | modules/field/tests/field_test.module | 21 | ||||
-rw-r--r-- | modules/simpletest/tests/entity_query.test | 54 |
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 |