diff --git modules/entity/entity.controller.inc modules/entity/entity.controller.inc new file mode 100644 index 0000000..a13c942 --- /dev/null +++ modules/entity/entity.controller.inc @@ -0,0 +1,385 @@ + $value. + * + * @return + * An array of entity objects indexed by their ids. + */ + public function load($ids = array(), $conditions = array()); +} + +/** + * Default implementation of DrupalEntityControllerInterface. + * + * This class can be used as-is by most simple entity types. Entity types + * requiring special handling can extend the class. + */ +class DrupalDefaultEntityController implements DrupalEntityControllerInterface { + + /** + * Static cache of entities. + * + * @var array + */ + protected $entityCache; + + /** + * Entity type for this controller instance. + * + * @var string + */ + protected $entityType; + + /** + * Array of information about the entity. + * + * @var array + * + * @see entity_get_info() + */ + protected $entityInfo; + + /** + * Additional arguments to pass to hook_TYPE_load(). + * + * Set before calling DrupalDefaultEntityController::attachLoad(). + * + * @var array + */ + protected $hookLoadArguments; + + /** + * Name of the entity's ID field in the entity database table. + * + * @var string + */ + protected $idKey; + + /** + * Name of entity's revision database table field, if it supports revisions. + * + * Has the value FALSE if this entity does not use revisions. + * + * @var string + */ + protected $revisionKey; + + /** + * The table that stores revisions, if the entity supports revisions. + * + * @var string + */ + protected $revisionTable; + + /** + * Whether this entity type should use the static cache. + * + * Set by entity info. + * + * @var boolean + */ + protected $cache; + + /** + * Constructor: sets basic variables. + */ + public function __construct($entityType) { + $this->entityType = $entityType; + $this->entityInfo = entity_get_info($entityType); + $this->entityCache = array(); + $this->hookLoadArguments = array(); + $this->idKey = $this->entityInfo['entity keys']['id']; + + // Check if the entity type supports revisions. + if (!empty($this->entityInfo['entity keys']['revision'])) { + $this->revisionKey = $this->entityInfo['entity keys']['revision']; + $this->revisionTable = $this->entityInfo['revision table']; + } + else { + $this->revisionKey = FALSE; + } + + // Check if the entity type supports static caching of loaded entities. + $this->cache = !empty($this->entityInfo['static cache']); + } + + /** + * Implements DrupalEntityControllerInterface::resetCache(). + */ + public function resetCache(array $ids = NULL) { + if (isset($ids)) { + foreach ($ids as $id) { + unset($this->entityCache[$id]); + } + } + else { + $this->entityCache = array(); + } + } + + /** + * Implements DrupalEntityControllerInterface::load(). + */ + public function load($ids = array(), $conditions = array()) { + $entities = array(); + + // Revisions are not statically cached, and require a different query to + // other conditions, so separate the revision id into its own variable. + if ($this->revisionKey && isset($conditions[$this->revisionKey])) { + $revision_id = $conditions[$this->revisionKey]; + unset($conditions[$this->revisionKey]); + } + else { + $revision_id = FALSE; + } + + // Create a new variable which is either a prepared version of the $ids + // array for later comparison with the entity cache, or FALSE if no $ids + // were passed. The $ids array is reduced as items are loaded from cache, + // and we need to know if it's empty for this reason to avoid querying the + // database when all requested entities are loaded from cache. + $passed_ids = !empty($ids) ? array_flip($ids) : FALSE; + // Try to load entities from the static cache, if the entity type supports + // static caching. + if ($this->cache && !$revision_id) { + $entities += $this->cacheGet($ids, $conditions); + // If any entities were loaded, remove them from the ids still to load. + if ($passed_ids) { + $ids = array_keys(array_diff_key($passed_ids, $entities)); + } + } + + // Load any remaining entities from the database. This is the case if $ids + // is set to FALSE (so we load all entities), if there are any ids left to + // load, if loading a revision, or if $conditions was passed without $ids. + if ($ids === FALSE || $ids || $revision_id || ($conditions && !$passed_ids)) { + // Build the query. + $query = $this->buildQuery($ids, $conditions, $revision_id); + $queried_entities = $query + ->execute() + ->fetchAllAssoc($this->idKey); + } + + // Pass all entities loaded from the database through $this->attachLoad(), + // which attaches fields (if supported by the entity type) and calls the + // entity type specific load callback, for example hook_node_load(). + if (!empty($queried_entities)) { + $this->attachLoad($queried_entities, $revision_id); + $entities += $queried_entities; + } + + if ($this->cache) { + // Add entities to the cache if we are not loading a revision. + if (!empty($queried_entities) && !$revision_id) { + $this->cacheSet($queried_entities); + } + } + + // Ensure that the returned array is ordered the same as the original + // $ids array if this was passed in and remove any invalid ids. + if ($passed_ids) { + // Remove any invalid ids from the array. + $passed_ids = array_intersect_key($passed_ids, $entities); + foreach ($entities as $entity) { + $passed_ids[$entity->{$this->idKey}] = $entity; + } + $entities = $passed_ids; + } + + return $entities; + } + + /** + * Builds the query to load the entity. + * + * This has full revision support. For entities requiring special queries, + * the class can be extended, and the default query can be constructed by + * calling parent::buildQuery(). This is usually necessary when the object + * being loaded needs to be augmented with additional data from another + * table, such as loading node type into comments or vocabulary machine name + * into terms, however it can also support $conditions on different tables. + * See CommentController::buildQuery() or TaxonomyTermController::buildQuery() + * for examples. + * + * @param $ids + * An array of entity IDs, or FALSE to load all entities. + * @param $conditions + * An array of conditions in the form 'field' => $value. + * @param $revision_id + * The ID of the revision to load, or FALSE if this query is asking for the + * most current revision(s). + * + * @return SelectQuery + * A SelectQuery object for loading the entity. + */ + protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) { + $query = db_select($this->entityInfo['base table'], 'base'); + + $query->addTag($this->entityType . '_load_multiple'); + + if ($revision_id) { + $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id)); + } + elseif ($this->revisionKey) { + $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); + } + + // Add fields from the {entity} table. + $entity_fields = $this->entityInfo['schema_fields_sql']['base table']; + + if ($this->revisionKey) { + // Add all fields from the {entity_revision} table. + $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision table']); + // The id field is provided by entity, so remove it. + unset($entity_revision_fields[$this->idKey]); + + // Remove all fields from the base table that are also fields by the same + // name in the revision table. + $entity_field_keys = array_flip($entity_fields); + foreach ($entity_revision_fields as $key => $name) { + if (isset($entity_field_keys[$name])) { + unset($entity_fields[$entity_field_keys[$name]]); + } + } + $query->fields('revision', $entity_revision_fields); + } + + $query->fields('base', $entity_fields); + + if ($ids) { + $query->condition("base.{$this->idKey}", $ids, 'IN'); + } + if ($conditions) { + foreach ($conditions as $field => $value) { + $query->condition('base.' . $field, $value); + } + } + return $query; + } + + /** + * Attaches data to entities upon loading. + * This will attach fields, if the entity is fieldable. It calls + * hook_entity_load() for modules which need to add data to all entities. + * It also calls hook_TYPE_load() on the loaded entities. For example + * hook_node_load() or hook_user_load(). If your hook_TYPE_load() + * expects special parameters apart from the queried entities, you can set + * $this->hookLoadArguments prior to calling the method. + * See NodeController::attachLoad() for an example. + * + * @param $queried_entities + * Associative array of query results, keyed on the entity ID. + * @param $revision_id + * ID of the revision that was loaded, or FALSE if teh most current revision + * was loaded. + */ + protected function attachLoad(&$queried_entities, $revision_id = FALSE) { + // Attach fields. + if ($this->entityInfo['fieldable']) { + if ($revision_id) { + field_attach_load_revision($this->entityType, $queried_entities); + } + else { + field_attach_load($this->entityType, $queried_entities); + } + } + + // Call hook_entity_load(). + foreach (module_implements('entity_load') as $module) { + $function = $module . '_entity_load'; + $function($queried_entities, $this->entityType); + } + // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are + // always the queried entities, followed by additional arguments set in + // $this->hookLoadArguments. + $args = array_merge(array($queried_entities), $this->hookLoadArguments); + foreach (module_implements($this->entityInfo['load hook']) as $module) { + call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args); + } + } + + /** + * Gets entities from the static cache. + * + * @param $ids + * If not empty, return entities that match these IDs. + * @param $conditions + * If set, return entities that match all of these conditions. + * + * @return + * Array of entities from the entity cache. + */ + protected function cacheGet($ids, $conditions = array()) { + $entities = array(); + // Load any available entities from the internal cache. + if (!empty($this->entityCache)) { + if ($ids) { + $entities += array_intersect_key($this->entityCache, array_flip($ids)); + } + // If loading entities only by conditions, fetch all available entities + // from the cache. Entities which don't match are removed later. + elseif ($conditions) { + $entities = $this->entityCache; + } + } + + // Exclude any entities loaded from cache if they don't match $conditions. + // This ensures the same behavior whether loading from memory or database. + if ($conditions) { + foreach ($entities as $entity) { + $entity_values = (array) $entity; + if (array_diff_assoc($conditions, $entity_values)) { + unset($entities[$entity->{$this->idKey}]); + } + } + } + return $entities; + } + + /** + * Stores entities in the static entity cache. + * + * @param $entities + * Entities to store in the cache. + */ + protected function cacheSet($entities) { + $this->entityCache += $entities; + } +} diff --git modules/entity/entity.info modules/entity/entity.info new file mode 100644 index 0000000..2b94194 --- /dev/null +++ modules/entity/entity.info @@ -0,0 +1,8 @@ +; $Id$ +name = Entity +description = Entity API to add fields to entities like nodes and users. +package = Core +version = VERSION +core = 7.x +files[] = entity.controller.inc +files[] = entity.query.inc diff --git modules/entity/entity.module modules/entity/entity.module new file mode 100644 index 0000000..460222c --- /dev/null +++ modules/entity/entity.module @@ -0,0 +1,404 @@ +language; + + if (empty($entity_info)) { + if ($cache = cache_get("entity_info:$langcode")) { + $entity_info = $cache->data; + } + else { + $entity_info = module_invoke_all('entity_info'); + // Merge in default values. + foreach ($entity_info as $name => $data) { + $entity_info[$name] += array( + 'fieldable' => FALSE, + 'controller class' => 'DrupalDefaultEntityController', + 'static cache' => TRUE, + 'field cache' => TRUE, + 'load hook' => $name . '_load', + 'bundles' => array(), + 'view modes' => array(), + 'entity keys' => array(), + 'translation' => array(), + ); + $entity_info[$name]['entity keys'] += array( + 'revision' => '', + 'bundle' => '', + ); + foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) { + $entity_info[$name]['view modes'][$view_mode] += array( + 'custom settings' => FALSE, + ); + } + // If no bundle key is provided, assume a single bundle, named after + // the entity type. + if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) { + $entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label'])); + } + // Prepare entity schema fields SQL info for + // DrupalEntityControllerInterface::buildQuery(). + if (isset($entity_info[$name]['base table'])) { + $entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']); + if (isset($entity_info[$name]['revision table'])) { + $entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']); + } + } + } + // Let other modules alter the entity info. + drupal_alter('entity_info', $entity_info); + cache_set("entity_info:$langcode", $entity_info); + } + } + + if (empty($entity_type)) { + return $entity_info; + } + elseif (isset($entity_info[$entity_type])) { + return $entity_info[$entity_type]; + } +} + +/** + * Resets the cached information about entity types. + */ +function entity_info_cache_clear() { + drupal_static_reset('entity_get_info'); + // Clear all languages. + cache_clear_all('entity_info:', 'cache', TRUE); +} + +/** + * Helper function to extract id, vid, and bundle name from an entity. + * + * @param $entity_type + * The entity type; e.g. 'node' or 'user'. + * @param $entity + * The entity from which to extract values. + * @return + * A numerically indexed array (not a hash table) containing these + * elements: + * 0: primary id of the entity + * 1: revision id of the entity, or NULL if $entity_type is not versioned + * 2: bundle name of the entity + */ +function entity_extract_ids($entity_type, $entity) { + $info = entity_get_info($entity_type); + // Objects being created might not have id/vid yet. + $id = isset($entity->{$info['entity keys']['id']}) ? $entity->{$info['entity keys']['id']} : NULL; + $vid = ($info['entity keys']['revision'] && isset($entity->{$info['entity keys']['revision']})) ? $entity->{$info['entity keys']['revision']} : NULL; + // If no bundle key provided, then we assume a single bundle, named after the + // entity type. + $bundle = $info['entity keys']['bundle'] ? $entity->{$info['entity keys']['bundle']} : $entity_type; + return array($id, $vid, $bundle); +} + +/** + * Helper function to assemble an object structure with initial ids. + * + * This function can be seen as reciprocal to entity_extract_ids(). + * + * @param $entity_type + * The entity type; e.g. 'node' or 'user'. + * @param $ids + * A numerically indexed array, as returned by entity_extract_ids(), + * containing these elements: + * 0: primary id of the entity + * 1: revision id of the entity, or NULL if $entity_type is not versioned + * 2: bundle name of the entity, or NULL if $entity_type has no bundles + * @return + * An entity structure, initialized with the ids provided. + */ +function entity_create_stub_entity($entity_type, $ids) { + $entity = new stdClass(); + $info = entity_get_info($entity_type); + $entity->{$info['entity keys']['id']} = $ids[0]; + if (!empty($info['entity keys']['revision']) && isset($ids[1])) { + $entity->{$info['entity keys']['revision']} = $ids[1]; + } + if (!empty($info['entity keys']['bundle']) && isset($ids[2])) { + $entity->{$info['entity keys']['bundle']} = $ids[2]; + } + return $entity; +} + +/** + * Load entities from the database. + * + * This function should be used whenever you need to load more than one entity + * from the database. The entities are loaded into memory and will not require + * database access if loaded again during the same page request. + * + * The actual loading is done through a class that has to implement the + * DrupalEntityControllerInterface interface. By default, + * DrupalDefaultEntityController is used. Entity types can specify that a + * different class should be used by setting the 'controller class' key in + * hook_entity_info(). These classes can either implement the + * DrupalEntityControllerInterface interface, or, most commonly, extend the + * DrupalDefaultEntityController class. See node_entity_info() and the + * NodeController in node.module as an example. + * + * @see hook_entity_info() + * @see DrupalEntityControllerInterface + * @see DrupalDefaultEntityController + * @see EntityFieldQuery + * + * @param $entity_type + * The entity type to load, e.g. node or user. + * @param $ids + * An array of entity IDs, or FALSE to load all entities. + * @param $conditions + * (deprecated) An associative array of conditions on the base table, where + * the keys are the database fields and the values are the values those + * fields must have. Instead, it is preferable to use EntityFieldQuery to + * retrieve a list of entity IDs loadable by this function. + * @param $reset + * Whether to reset the internal cache for the requested entity type. + * + * @return + * An array of entity objects indexed by their ids. + * + * @todo Remove $conditions in Drupal 8. + */ +function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) { + if ($reset) { + entity_get_controller($entity_type)->resetCache(); + } + return entity_get_controller($entity_type)->load($ids, $conditions); +} + +/** + * Loads the unchanged, i.e. not modified, entity from the database. + * + * Unlike entity_load() this function ensures the entity is directly loaded from + * the database, thus bypassing any static cache. In particular, this function + * is useful to determine changes by comparing the entity being saved to the + * stored entity. + * + * @param $entity_type + * The entity type to load, e.g. node or user. + * @param $id + * The id of the entity to load. + * + * @return + * The unchanged entity, or FALSE if the entity cannot be loaded. + */ +function entity_load_unchanged($entity_type, $id) { + entity_get_controller($entity_type)->resetCache(array($id)); + $result = entity_get_controller($entity_type)->load(array($id)); + return reset($result); +} + +/** + * Get the entity controller class for an entity type. + */ +function entity_get_controller($entity_type) { + $controllers = &drupal_static(__FUNCTION__, array()); + if (!isset($controllers[$entity_type])) { + $type_info = entity_get_info($entity_type); + $class = $type_info['controller class']; + $controllers[$entity_type] = new $class($entity_type); + } + return $controllers[$entity_type]; +} + +/** + * Invoke hook_entity_prepare_view(). + * + * If adding a new entity similar to nodes, comments or users, you should + * invoke this function during the ENTITY_build_content() or + * ENTITY_view_multiple() phases of rendering to allow other modules to alter + * the objects during this phase. This is needed for situations where + * information needs to be loaded outside of ENTITY_load() - particularly + * when loading entities into one another - i.e. a user object into a node, due + * to the potential for unwanted side-effects such as caching and infinite + * recursion. By convention, entity_prepare_view() is called after + * field_attach_prepare_view() to allow entity level hooks to act on content + * loaded by field API. + * @see hook_entity_prepare_view() + * + * @param $entity_type + * The type of entity, i.e. 'node', 'user'. + * @param $entities + * The entity objects which are being prepared for view, keyed by object ID. + */ +function entity_prepare_view($entity_type, $entities) { + // To ensure hooks are only run once per entity, check for an + // entity_view_prepared flag and only process items without it. + // @todo: resolve this more generally for both entity and field level hooks. + $prepare = array(); + foreach ($entities as $id => $entity) { + if (empty($entity->entity_view_prepared)) { + // Add this entity to the items to be prepared. + $prepare[$id] = $entity; + + // Mark this item as prepared. + $entity->entity_view_prepared = TRUE; + } + } + + if (!empty($prepare)) { + module_invoke_all('entity_prepare_view', $prepare, $entity_type); + } +} + +/** + * Returns the uri elements of an entity. + * + * @param $entity_type + * The entity type; e.g. 'node' or 'user'. + * @param $entity + * The entity for which to generate a path. + * @return + * An array containing the 'path' and 'options' keys used to build the uri of + * the entity, and matching the signature of url(). NULL if the entity has no + * uri of its own. + */ +function entity_uri($entity_type, $entity) { + // This check enables the URI of an entity to be easily overridden from what + // the callback for the entity type or bundle would return, and it helps + // minimize performance overhead when entity_uri() is called multiple times + // for the same entity. + if (!isset($entity->uri)) { + $info = entity_get_info($entity_type); + list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); + + // A bundle-specific callback takes precedence over the generic one for the + // entity type. + if (isset($info['bundles'][$bundle]['uri callback'])) { + $uri_callback = $info['bundles'][$bundle]['uri callback']; + } + elseif (isset($info['uri callback'])) { + $uri_callback = $info['uri callback']; + } + else { + $uri_callback = NULL; + } + + // Invoke the callback to get the URI. If there is no callback, set the + // entity's 'uri' property to FALSE to indicate that it is known to not have + // a URI. + if (isset($uri_callback) && function_exists($uri_callback)) { + $entity->uri = $uri_callback($entity); + if (!isset($entity->uri['options'])) { + $entity->uri['options'] = array(); + } + // Pass the entity data to url() so that alter functions do not need to + // lookup this entity again. + $entity->uri['options']['entity_type'] = $entity_type; + $entity->uri['options']['entity'] = $entity; + } + else { + $entity->uri = FALSE; + } + } + return $entity->uri ? $entity->uri : NULL; +} + +/** + * Returns the label of an entity. + * + * See the 'label callback' component of the hook_entity_info() return value + * for more information. + * + * @param $entity_type + * The entity type; e.g., 'node' or 'user'. + * @param $entity + * The entity for which to generate the label. + * + * @return + * The entity label, or FALSE if not found. + */ +function entity_label($entity_type, $entity) { + $label = FALSE; + $info = entity_get_info($entity_type); + if (isset($info['label callback']) && function_exists($info['label callback'])) { + $label = $info['label callback']($entity); + } + elseif (!empty($info['entity keys']['label']) && isset($entity->{$info['entity keys']['label']})) { + $label = $entity->{$info['entity keys']['label']}; + } + + return $label; +} + +/** + * Helper function for attaching field API validation to entity forms. + */ +function entity_form_field_validate($entity_type, $form, &$form_state) { + // All field attach API functions act on an entity object, but during form + // validation, we don't have one. $form_state contains the entity as it was + // prior to processing the current form submission, and we must not update it + // until we have fully validated the submitted input. Therefore, for + // validation, act on a pseudo entity created out of the form values. + $pseudo_entity = (object) $form_state['values']; + field_attach_form_validate($entity_type, $pseudo_entity, $form, $form_state); +} + +/** + * Helper function for copying submitted values to entity properties for simple entity forms. + * + * During the submission handling of an entity form's "Save", "Preview", and + * possibly other buttons, the form state's entity needs to be updated with the + * submitted form values. Each entity form implements its own builder function + * for doing this, appropriate for the particular entity and form, whereas + * modules may specify additional builder functions in $form['#entity_builders'] + * for copying the form values of added form elements to entity properties. + * Many of the main entity builder functions can call this helper function to + * re-use its logic of copying $form_state['values'][PROPERTY] values to + * $entity->PROPERTY for all entries in $form_state['values'] that are not field + * data, and calling field_attach_submit() to copy field data. Apart from that + * this helper invokes any additional builder functions that have been specified + * in $form['#entity_builders']. + * + * For some entity forms (e.g., forms with complex non-field data and forms that + * simultaneously edit multiple entities), this behavior may be inappropriate, + * so the builder function for such forms needs to implement the required + * functionality instead of calling this function. + */ +function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) { + $info = entity_get_info($entity_type); + list(, , $bundle) = entity_extract_ids($entity_type, $entity); + + // Copy top-level form values that are not for fields to entity properties, + // without changing existing entity properties that are not being edited by + // this form. Copying field values must be done using field_attach_submit(). + $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $bundle)) : $form_state['values']; + foreach ($values_excluding_fields as $key => $value) { + $entity->$key = $value; + } + + // Invoke all specified builders for copying form values to entity properties. + if (isset($form['#entity_builders'])) { + foreach ($form['#entity_builders'] as $function) { + $function($entity_type, $entity, $form, $form_state); + } + } + + // Copy field values to the entity. + if ($info['fieldable']) { + field_attach_submit($entity_type, $entity, $form, $form_state); + } +} diff --git modules/entity/entity.query.inc modules/entity/entity.query.inc new file mode 100644 index 0000000..dabbe2a --- /dev/null +++ modules/entity/entity.query.inc @@ -0,0 +1,839 @@ +changed), field values, and generic entity meta data (bundle, + * entity type, entity id, and revision ID). It is not possible to query across + * multiple entity types. For example, there is no facility to find published + * nodes written by users created in the last hour, as this would require + * querying both node->status and user->created. + * + * Normally we would not want to have public properties on the object, as that + * allows the object's state to become inconsistent too easily. However, this + * class's standard use case involves primarily code that does need to have + * direct access to the collected properties in order to handle alternate + * execution routines. We therefore use public properties for simplicity. Note + * that code that is simply creating and running a field query should still use + * the appropriate methods add conditions on the query. + * + * Storage engines are not required to support every type of query. By default, + * an EntityFieldQueryException will be raised if an unsupported condition is + * specified or if the query has field conditions or sorts that are stored in + * different field storage engines. However, this logic can be overridden in + * hook_entity_query(). + * + * Also note that this query does not automatically respect entity access + * restrictions. Node access control is performed by the SQL storage engine but + * other storage engines might not do this. + */ +class EntityFieldQuery { + /** + * Indicates that both deleted and non-deleted fields should be returned. + * + * @see EntityFieldQuery::deleted() + */ + const RETURN_ALL = NULL; + + /** + * TRUE if the query has already been altered, FALSE if it hasn't. + * + * Used in alter hooks to check for cloned queries that have already been + * altered prior to the clone (for example, the pager count query). + * + * @var boolean + */ + public $altered = FALSE; + + /** + * Associative array of entity-generic metadata conditions. + * + * @var array + * + * @see EntityFieldQuery::entityCondition() + */ + public $entityConditions = array(); + + /** + * List of field conditions. + * + * @var array + * + * @see EntityFieldQuery::fieldCondition() + */ + public $fieldConditions = array(); + + /** + * List of property conditions. + * + * @var array + * + * @see EntityFieldQuery::propertyCondition() + */ + public $propertyConditions = array(); + + /** + * List of order clauses. + * + * @var array + */ + public $order = array(); + + /** + * The query range. + * + * @var array + * + * @see EntityFieldQuery::range() + */ + public $range = array(); + + /** + * The query pager data. + * + * @var array + * + * @see EntityFieldQuery::pager() + */ + public $pager = array(); + + /** + * Query behavior for deleted data. + * + * TRUE to return only deleted data, FALSE to return only non-deleted data, + * EntityFieldQuery::RETURN_ALL to return everything. + * + * @see EntityFieldQuery::deleted() + */ + public $deleted = FALSE; + + /** + * A list of field arrays used. + * + * Field names passed to EntityFieldQuery::fieldCondition() and + * EntityFieldQuery::fieldOrderBy() are run through field_info_field() before + * stored in this array. This way, the elements of this array are field + * arrays. + * + * @var array + */ + public $fields = array(); + + /** + * TRUE if this is a count query, FALSE if it isn't. + * + * @var boolean + */ + public $count = FALSE; + + /** + * Flag indicating whether this is querying current or all revisions. + * + * @var int + * + * @see EntityFieldQuery::age() + */ + public $age = FIELD_LOAD_CURRENT; + + /** + * A list of the tags added to this query. + * + * @var array + * + * @see EntityFieldQuery::addTag() + */ + public $tags = array(); + + /** + * A list of metadata added to this query. + * + * @var array + * + * @see EntityFieldQuery::addMetaData() + */ + public $metaData = array(); + + /** + * The ordered results. + * + * @var array + * + * @see EntityFieldQuery::execute(). + */ + public $orderedResults = array(); + + /** + * The method executing the query, if it is overriding the default. + * + * @var string + * + * @see EntityFieldQuery::execute(). + */ + public $executeCallback = ''; + + /** + * Adds a condition on entity-generic metadata. + * + * If the overall query contains only entity conditions or ordering, or if + * there are property conditions, then specifying the entity type is + * mandatory. If there are field conditions or ordering but no property + * conditions or ordering, then specifying an entity type is optional. While + * the field storage engine might support field conditions on more than one + * entity type, there is no way to query across multiple entity base tables by + * default. To specify the entity type, pass in 'entity_type' for $name, + * the type as a string for $value, and no $operator (it's disregarded). + * + * 'bundle', 'revision_id' and 'entity_id' have no such restrictions. + * + * Note: The "comment" and "taxonomy_term" entity types don't support bundle + * conditions. For "taxonomy_term", propertyCondition('vid') can be used + * instead. + * + * @param $name + * 'entity_type', 'bundle', 'revision_id' or 'entity_id'. + * @param $value + * The value for $name. In most cases, this is a scalar. For more complex + * options, it is an array. The meaning of each element in the array is + * dependent on $operator. + * @param $operator + * Possible values: + * - '=', '!=', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These + * operators expect $value to be a literal of the same type as the + * column. + * - 'IN', 'NOT IN': These operators expect $value to be an array of + * literals of the same type as the column. + * - 'BETWEEN': This operator expects $value to be an array of two literals + * of the same type as the column. + * + * @return EntityFieldQuery + * The called object. + */ + public function entityCondition($name, $value, $operator = NULL) { + $this->entityConditions[$name] = array( + 'value' => $value, + 'operator' => $operator, + ); + return $this; + } + + /** + * Adds a condition on field values. + * + * @param $field + * Either a field name or a field array. + * @param $column + * A column defined in the hook_field_schema() of this field. If this is + * omitted then the query will find only entities that have data in this + * field, using the entity and property conditions if there are any. + * @param $value + * The value to test the column value against. In most cases, this is a + * scalar. For more complex options, it is an array. The meaning of each + * element in the array is dependent on $operator. + * @param $operator + * Possible values: + * - '=', '!=', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These + * operators expect $value to be a literal of the same type as the + * column. + * - 'IN', 'NOT IN': These operators expect $value to be an array of + * literals of the same type as the column. + * - 'BETWEEN': This operator expects $value to be an array of two literals + * of the same type as the column. + * @param $delta_group + * An arbitrary identifier: conditions in the same group must have the same + * $delta_group. For example, let's presume a multivalue field which has + * two columns, 'color' and 'shape', and for entity id 1, there are two + * values: red/square and blue/circle. Entity ID 1 does not have values + * corresponding to 'red circle', however if you pass 'red' and 'circle' as + * conditions, it will appear in the results - by default queries will run + * against any combination of deltas. By passing the conditions with the + * same $delta_group it will ensure that only values attached to the same + * delta are matched, and entity 1 would then be excluded from the results. + * @param $language_group + * An arbitrary identifier: conditions in the same group must have the same + * $language_group. + * + * @return EntityFieldQuery + * The called object. + */ + public function fieldCondition($field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { + if (is_scalar($field)) { + $field = field_info_field($field); + } + // Ensure the same index is used for fieldConditions as for fields. + $index = count($this->fields); + $this->fields[$index] = $field; + if (isset($column)) { + $this->fieldConditions[$index] = array( + 'field' => $field, + 'column' => $column, + 'value' => $value, + 'operator' => $operator, + 'delta_group' => $delta_group, + 'language_group' => $language_group, + ); + } + return $this; + } + + /** + * Adds a condition on an entity-specific property. + * + * An $entity_type must be specified by calling + * EntityFieldCondition::entityCondition('entity_type', $entity_type) before + * executing the query. Also, by default only entities stored in SQL are + * supported; however, EntityFieldQuery::executeCallback can be set to handle + * different entity storage. + * + * @param $column + * A column defined in the hook_schema() of the base table of the entity. + * @param $value + * The value to test the field against. In most cases, this is a scalar. For + * more complex options, it is an array. The meaning of each element in the + * array is dependent on $operator. + * @param $operator + * Possible values: + * - '=', '!=', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These + * operators expect $value to be a literal of the same type as the + * column. + * - 'IN', 'NOT IN': These operators expect $value to be an array of + * literals of the same type as the column. + * - 'BETWEEN': This operator expects $value to be an array of two literals + * of the same type as the column. + * The operator can be omitted, and will default to 'IN' if the value is an + * array, or to '=' otherwise. + * + * @return EntityFieldQuery + * The called object. + */ + public function propertyCondition($column, $value, $operator = NULL) { + $this->propertyConditions[] = array( + 'column' => $column, + 'value' => $value, + 'operator' => $operator, + ); + return $this; + } + + /** + * Orders the result set by entity-generic metadata. + * + * If called multiple times, the query will order by each specified column in + * the order this method is called. + * + * Note: The "comment" and "taxonomy_term" entity types don't support ordering + * by bundle. For "taxonomy_term", propertyOrderBy('vid') can be used instead. + * + * @param $name + * 'entity_type', 'bundle', 'revision_id' or 'entity_id'. + * @param $direction + * The direction to sort. Legal values are "ASC" and "DESC". + * + * @return EntityFieldQuery + * The called object. + */ + public function entityOrderBy($name, $direction = 'ASC') { + $this->order[] = array( + 'type' => 'entity', + 'specifier' => $name, + 'direction' => $direction, + ); + return $this; + } + + /** + * Orders the result set by a given field column. + * + * If called multiple times, the query will order by each specified column in + * the order this method is called. + * + * @param $field + * Either a field name or a field array. + * @param $column + * A column defined in the hook_field_schema() of this field. entity_id and + * bundle can also be used. + * @param $direction + * The direction to sort. Legal values are "ASC" and "DESC". + * + * @return EntityFieldQuery + * The called object. + */ + public function fieldOrderBy($field, $column, $direction = 'ASC') { + if (is_scalar($field)) { + $field = field_info_field($field); + } + // Save the index used for the new field, for later use in field storage. + $index = count($this->fields); + $this->fields[$index] = $field; + $this->order[] = array( + 'type' => 'field', + 'specifier' => array( + 'field' => $field, + 'index' => $index, + 'column' => $column, + ), + 'direction' => $direction, + ); + return $this; + } + + /** + * Orders the result set by an entity-specific property. + * + * An $entity_type must be specified by calling + * EntityFieldCondition::entityCondition('entity_type', $entity_type) before + * executing the query. + * + * If called multiple times, the query will order by each specified column in + * the order this method is called. + * + * @param $column + * The column on which to order. + * @param $direction + * The direction to sort. Legal values are "ASC" and "DESC". + * + * @return EntityFieldQuery + * The called object. + */ + public function propertyOrderBy($column, $direction = 'ASC') { + $this->order[] = array( + 'type' => 'property', + 'specifier' => $column, + 'direction' => $direction, + ); + return $this; + } + + /** + * Sets the query to be a count query only. + * + * @return EntityFieldQuery + * The called object. + */ + public function count() { + $this->count = TRUE; + return $this; + } + + /** + * Restricts a query to a given range in the result set. + * + * @param $start + * The first entity from the result set to return. If NULL, removes any + * range directives that are set. + * @param $length + * The number of entities to return from the result set. + * + * @return EntityFieldQuery + * The called object. + */ + public function range($start = NULL, $length = NULL) { + $this->range = array( + 'start' => $start, + 'length' => $length, + ); + return $this; + } + + /** + * Enable a pager for the query. + * + * @param $limit + * An integer specifying the number of elements per page. If passed a false + * value (FALSE, 0, NULL), the pager is disabled. + * @param $element + * An optional integer to distinguish between multiple pagers on one page. + * If not provided, one is automatically calculated. + * + * @return EntityFieldQuery + * The called object. + */ + public function pager($limit = 10, $element = NULL) { + if (!isset($element)) { + $element = PagerDefault::$maxElement++; + } + elseif ($element >= PagerDefault::$maxElement) { + PagerDefault::$maxElement = $element + 1; + } + + $this->pager = array( + 'limit' => $limit, + 'element' => $element, + ); + return $this; + } + + /** + * Enable sortable tables for this query. + * + * @param $headers + * An EFQ Header array based on which the order clause is added to the query. + * + * @return EntityFieldQuery + * The called object. + */ + public function tableSort(&$headers) { + // If 'field' is not initialized, the header columns aren't clickable + foreach ($headers as $key =>$header) { + if (is_array($header) && isset($header['specifier'])) { + $headers[$key]['field'] = ''; + } + } + + $order = tablesort_get_order($headers); + $direction = tablesort_get_sort($headers); + foreach ($headers as $header) { + if (is_array($header) && ($header['data'] == $order['name'])) { + if ($header['type'] == 'field') { + $this->fieldOrderBy($header['specifier']['field'], $header['specifier']['column'], $direction); + } + else { + $header['direction'] = $direction; + $this->order[] = $header; + } + } + } + + return $this; + } + + /** + * Filters on the data being deleted. + * + * @param $deleted + * TRUE to only return deleted data, FALSE to return non-deleted data, + * EntityFieldQuery::RETURN_ALL to return everything. Defaults to FALSE. + * + * @return EntityFieldQuery + * The called object. + */ + public function deleted($deleted = TRUE) { + $this->deleted = $deleted; + return $this; + } + + /** + * Queries the current or every revision. + * + * Note that this only affects field conditions. Property conditions always + * apply to the current revision. + * @TODO: Once revision tables have been cleaned up, revisit this. + * + * @param $age + * - FIELD_LOAD_CURRENT (default): Query the most recent revisions for all + * entities. The results will be keyed by entity type and entity ID. + * - FIELD_LOAD_REVISION: Query all revisions. The results will be keyed by + * entity type and entity revision ID. + * + * @return EntityFieldQuery + * The called object. + */ + public function age($age) { + $this->age = $age; + return $this; + } + + /** + * Adds a tag to the query. + * + * Tags are strings that mark a query so that hook_query_alter() and + * hook_query_TAG_alter() implementations may decide if they wish to alter + * the query. A query may have any number of tags, and they must be valid PHP + * identifiers (composed of letters, numbers, and underscores). For example, + * queries involving nodes that will be displayed for a user need to add the + * tag 'node_access', so that the node module can add access restrictions to + * the query. + * + * If an entity field query has tags, it must also have an entity type + * specified, because the alter hook will need the entity base table. + * + * @param string $tag + * The tag to add. + * + * @return EntityFieldQuery + * The called object. + */ + public function addTag($tag) { + $this->tags[$tag] = $tag; + return $this; + } + + /** + * Adds additional metadata to the query. + * + * Sometimes a query may need to provide additional contextual data for the + * alter hook. The alter hook implementations may then use that information + * to decide if and how to take action. + * + * @param $key + * The unique identifier for this piece of metadata. Must be a string that + * follows the same rules as any other PHP identifier. + * @param $object + * The additional data to add to the query. May be any valid PHP variable. + * + * @return EntityFieldQuery + * The called object. + */ + public function addMetaData($key, $object) { + $this->metaData[$key] = $object; + return $this; + } + + /** + * Executes the query. + * + * After executing the query, $this->orderedResults will contain a list of + * the same stub entities in the order returned by the query. This is only + * relevant if there are multiple entity types in the returned value and + * a field ordering was requested. In every other case, the returned value + * contains everything necessary for processing. + * + * @return + * Either a number if count() was called or an array of associative + * arrays of stub entities. The outer array keys are entity types, and the + * inner array keys are the relevant ID. (In most this cases this will be + * the entity ID. The only exception is when age=FIELD_LOAD_REVISION is used + * and field conditions or sorts are present -- in this case, the key will + * be the revision ID.) The inner array values are always stub entities, as + * returned by entity_create_stub_entity(). To traverse the returned array: + * @code + * foreach ($query->execute() as $entity_type => $entities) { + * foreach ($entities as $entity_id => $entity) { + * @endcode + * Note if the entity type is known, then the following snippet will load + * the entities found: + * @code + * $result = $query->execute(); + * $entities = entity_load($my_type, array_keys($result[$my_type])); + * @endcode + */ + public function execute() { + // Give a chance to other modules to alter the query. + drupal_alter('entity_query', $this); + $this->altered = TRUE; + + // Initialize the pager. + $this->initializePager(); + + // Execute the query using the correct callback. + $result = call_user_func($this->queryCallback(), $this); + + 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; + } + // 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 array($this, 'propertyQuery'); + } + // If no override, find the storage engine to be used. + foreach ($this->fields as $field) { + if (!isset($storage)) { + $storage = $field['storage']['module']; + } + elseif ($storage != $field['storage']['module']) { + throw new EntityFieldQueryException(t("Can't handle more than one field storage engine")); + } + } + if ($storage) { + // Use hook_field_storage_query() from the field storage. + return $storage . '_field_storage_query'; + } + else { + throw new EntityFieldQueryException(t("Field storage engine not found.")); + } + } + + /** + * Queries entity tables in SQL for property conditions and sorts. + * + * This method is only used if there are no field conditions and sorts. + * + * @return + * See EntityFieldQuery::execute(). + */ + protected function propertyQuery() { + if (empty($this->entityConditions['entity_type'])) { + throw new EntityFieldQueryException(t('For this query an entity type must be specified.')); + } + $entity_type = $this->entityConditions['entity_type']['value']; + $entity_info = entity_get_info($entity_type); + if (empty($entity_info['base table'])) { + throw new EntityFieldQueryException(t('Entity %entity has no base table.', array('%entity' => $entity_type))); + } + $base_table = $entity_info['base table']; + $base_table_schema = drupal_get_schema($base_table); + $select_query = db_select($base_table); + $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type)); + // Process the property conditions. + foreach ($this->propertyConditions as $property_condition) { + $this->addCondition($select_query, "$base_table." . $property_condition['column'], $property_condition); + } + // Process the four possible entity condition. + // The id field is always present in entity keys. + $sql_field = $entity_info['entity keys']['id']; + $id_map['entity_id'] = $sql_field; + $select_query->addField($base_table, $sql_field, 'entity_id'); + if (isset($this->entityConditions['entity_id'])) { + $this->addCondition($select_query, $sql_field, $this->entityConditions['entity_id']); + } + + // If there is a revision key defined, use it. + if (!empty($entity_info['entity keys']['revision'])) { + $sql_field = $entity_info['entity keys']['revision']; + $select_query->addField($base_table, $sql_field, 'revision_id'); + if (isset($this->entityConditions['revision_id'])) { + $this->addCondition($select_query, $sql_field, $this->entityConditions['revision_id']); + } + } + else { + $sql_field = 'revision_id'; + $select_query->addExpression('NULL', 'revision_id'); + } + $id_map['revision_id'] = $sql_field; + + // Handle bundles. + if (!empty($entity_info['entity keys']['bundle'])) { + $sql_field = $entity_info['entity keys']['bundle']; + $having = FALSE; + + if (!empty($base_table_schema['fields'][$sql_field])) { + $select_query->addField($base_table, $sql_field, 'bundle'); + } + } + else { + $sql_field = 'bundle'; + $select_query->addExpression(':bundle', 'bundle', array(':bundle' => $entity_type)); + $having = TRUE; + } + $id_map['bundle'] = $sql_field; + if (isset($this->entityConditions['bundle'])) { + $this->addCondition($select_query, $sql_field, $this->entityConditions['bundle'], $having); + } + + // Order the query. + foreach ($this->order as $order) { + if ($order['type'] == 'entity') { + $key = $order['specifier']; + if (!isset($id_map[$key])) { + throw new EntityFieldQueryException(t('Do not know how to order on @key for @entity_type', array('@key' => $key, '@entity_type' => $entity_type))); + } + $select_query->orderBy($id_map[$key], $order['direction']); + } + elseif ($order['type'] == 'property') { + $select_query->orderBy("$base_table." . $order['specifier'], $order['direction']); + } + } + + return $this->finishQuery($select_query); + } + + /** + * Get the total number of results and initialize a pager for the query. + * + * This query can be detected by checking for ($this->pager && $this->count), + * which allows a driver to return 0 from the count query and disable + * the pager. + */ + function initializePager() { + if ($this->pager && !$this->count) { + $page = pager_find_page($this->pager['element']); + $count_query = clone $this; + $this->pager['total'] = $count_query->count()->execute(); + $this->pager['start'] = $page * $this->pager['limit']; + pager_default_initialize($this->pager['total'], $this->pager['limit'], $this->pager['element']); + $this->range($this->pager['start'], $this->pager['limit']); + } + } + + /** + * Finishes the query. + * + * Adds tags, metaData, range and returns the requested list or count. + * + * @param SelectQuery $select_query + * A SelectQuery which has entity_type, entity_id, revision_id and bundle + * fields added. + * @param $id_key + * Which field's values to use as the returned array keys. + * + * @return + * See EntityFieldQuery::execute(). + */ + function finishQuery($select_query, $id_key = 'entity_id') { + foreach ($this->tags as $tag) { + $select_query->addTag($tag); + } + foreach ($this->metaData as $key => $object) { + $select_query->addMetaData($key, $object); + } + $select_query->addMetaData('entity_field_query', $this); + if ($this->range) { + $select_query->range($this->range['start'], $this->range['length']); + } + if ($this->count) { + return $select_query->countQuery()->execute()->fetchField(); + } + $return = array(); + foreach ($select_query->execute() as $partial_entity) { + $bundle = isset($partial_entity->bundle) ? $partial_entity->bundle : NULL; + $entity = entity_create_stub_entity($partial_entity->entity_type, array($partial_entity->entity_id, $partial_entity->revision_id, $bundle)); + $return[$partial_entity->entity_type][$partial_entity->$id_key] = $entity; + $this->ordered_results[] = $partial_entity; + } + return $return; + } + + /** + * Adds a condition to an already built SelectQuery (internal function). + * + * This is a helper for hook_entity_query() and hook_field_storage_query(). + * + * @param SelectQuery $select_query + * A SelectQuery object. + * @param $sql_field + * The name of the field. + * @param $condition + * A condition as described in EntityFieldQuery::fieldCondition() and + * EntityFieldQuery::entityCondition(). + * @param $having + * HAVING or WHERE. This is necessary because SQL can't handle WHERE + * conditions on aliased columns. + */ + public function addCondition(SelectQuery $select_query, $sql_field, $condition, $having = FALSE) { + $method = $having ? 'havingCondition' : 'condition'; + $like_prefix = ''; + switch ($condition['operator']) { + case 'CONTAINS': + $like_prefix = '%'; + case 'STARTS_WITH': + $select_query->$method($sql_field, $like_prefix . db_like($condition['value']) . '%', 'LIKE'); + break; + default: + $select_query->$method($sql_field, $condition['value'], $condition['operator']); + } + } + +} diff --git modules/entity/tests/entity_cache_test.info modules/entity/tests/entity_cache_test.info new file mode 100644 index 0000000..01c6d5d --- /dev/null +++ modules/entity/tests/entity_cache_test.info @@ -0,0 +1,8 @@ +; $Id$ +name = "Entity cache test" +description = "Support module for testing entity cache." +package = Testing +version = VERSION +core = 7.x +dependencies[] = entity_cache_test_dependency +hidden = TRUE diff --git modules/entity/tests/entity_cache_test.module modules/entity/tests/entity_cache_test.module new file mode 100644 index 0000000..b1daf68 --- /dev/null +++ modules/entity/tests/entity_cache_test.module @@ -0,0 +1,28 @@ + array( + 'label' => 'Entity Cache Test', + ), + ); +} diff --git modules/entity/tests/entity_crud_hook_test.info modules/entity/tests/entity_crud_hook_test.info new file mode 100644 index 0000000..5cc2ad9 --- /dev/null +++ modules/entity/tests/entity_crud_hook_test.info @@ -0,0 +1,7 @@ +; $Id$ +name = "Entity CRUD Hooks Test" +description = "Support module for CRUD hook tests." +core = 7.x +package = Testing +version = VERSION +hidden = TRUE diff --git modules/entity/tests/entity_crud_hook_test.module modules/entity/tests/entity_crud_hook_test.module new file mode 100644 index 0000000..12252d1 --- /dev/null +++ modules/entity/tests/entity_crud_hook_test.module @@ -0,0 +1,267 @@ + 'Entity CRUD hooks', + 'description' => 'Tests the invocation of hooks when inserting, loading, updating or deleting an entity.', + 'group' => 'Entity API', + ); + } + + public function setUp() { + parent::setUp('entity_crud_hook_test', 'taxonomy', 'comment'); + } + + /** + * Pass if the message $text was set by one of the CRUD hooks in + * entity_crud_hook_test.module, i.e., if the $text is an element of + * $_SESSION['entity_crud_hook_test']. + * + * @param $text + * Plain text to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * @return + * TRUE on pass, FALSE on fail. + */ + protected function assertHookMessage($text, $message = NULL, $group = 'Other') { + if (!isset($message)) { + $message = $text; + } + return $this->assertTrue(array_search($text, $_SESSION['entity_crud_hook_test']) !== FALSE, $message, $group); + } + + /** + * Test hook invocations for CRUD operations on comments. + */ + public function testCommentHooks() { + $node = (object) array( + 'uid' => 1, + 'type' => 'article', + 'title' => 'Test node', + 'status' => 1, + 'comment' => 2, + 'promote' => 0, + 'sticky' => 0, + 'language' => LANGUAGE_NONE, + 'created' => REQUEST_TIME, + 'changed' => REQUEST_TIME, + ); + node_save($node); + $nid = $node->nid; + + $comment = (object) array( + 'cid' => NULL, + 'pid' => 0, + 'nid' => $nid, + 'uid' => 1, + 'subject' => 'Test comment', + 'created' => REQUEST_TIME, + 'changed' => REQUEST_TIME, + 'status' => 1, + 'language' => LANGUAGE_NONE, + ); + $_SESSION['entity_crud_hook_test'] = array(); + comment_save($comment); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $comment = comment_load($comment->cid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $comment->subject = 'New subject'; + comment_save($comment); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + comment_delete($comment->cid); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type comment'); + $this->assertHookMessage('entity_crud_hook_test_comment_delete called'); + } + + /** + * Test hook invocations for CRUD operations on files. + */ + public function testFileHooks() { + $url = 'public://entity_crud_hook_test.file'; + file_put_contents($url, 'Test test test'); + $file = (object) array( + 'fid' => NULL, + 'uid' => 1, + 'filename' => 'entity_crud_hook_test.file', + 'uri' => $url, + 'filemime' => 'text/plain', + 'filesize' => filesize($url), + 'status' => 1, + 'timestamp' => REQUEST_TIME, + ); + $_SESSION['entity_crud_hook_test'] = array(); + file_save($file); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $file = file_load($file->fid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $file->filename = 'new.entity_crud_hook_test.file'; + file_save($file); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + file_delete($file); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type file'); + $this->assertHookMessage('entity_crud_hook_test_file_delete called'); + } + + /** + * Test hook invocations for CRUD operations on nodes. + */ + public function testNodeHooks() { + $node = (object) array( + 'uid' => 1, + 'type' => 'article', + 'title' => 'Test node', + 'status' => 1, + 'comment' => 2, + 'promote' => 0, + 'sticky' => 0, + 'language' => LANGUAGE_NONE, + 'created' => REQUEST_TIME, + 'changed' => REQUEST_TIME, + ); + $_SESSION['entity_crud_hook_test'] = array(); + node_save($node); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $node = node_load($node->nid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $node->title = 'New title'; + node_save($node); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + node_delete($node->nid); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type node'); + $this->assertHookMessage('entity_crud_hook_test_node_delete called'); + } + + /** + * Test hook invocations for CRUD operations on taxonomy terms. + */ + public function testTaxonomyTermHooks() { + $vocabulary = (object) array( + 'name' => 'Test vocabulary', + 'machine_name' => 'test', + 'description' => NULL, + 'module' => 'entity_crud_hook_test', + ); + taxonomy_vocabulary_save($vocabulary); + + $term = (object) array( + 'vid' => $vocabulary->vid, + 'name' => 'Test term', + 'description' => NULL, + 'format' => 1, + ); + $_SESSION['entity_crud_hook_test'] = array(); + taxonomy_term_save($term); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $term = taxonomy_term_load($term->tid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $term->name = 'New name'; + taxonomy_term_save($term); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + taxonomy_term_delete($term->tid); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_term'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_delete called'); + } + + /** + * Test hook invocations for CRUD operations on taxonomy vocabularies. + */ + public function testTaxonomyVocabularyHooks() { + $vocabulary = (object) array( + 'name' => 'Test vocabulary', + 'machine_name' => 'test', + 'description' => NULL, + 'module' => 'entity_crud_hook_test', + ); + $_SESSION['entity_crud_hook_test'] = array(); + taxonomy_vocabulary_save($vocabulary); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $vocabulary = taxonomy_vocabulary_load($vocabulary->vid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $vocabulary->name = 'New name'; + taxonomy_vocabulary_save($vocabulary); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + taxonomy_vocabulary_delete($vocabulary->vid); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary'); + $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_delete called'); + } + + /** + * Test hook invocations for CRUD operations on users. + */ + public function testUserHooks() { + $edit = array( + 'name' => 'Test user', + 'mail' => 'test@example.com', + 'created' => REQUEST_TIME, + 'status' => 1, + 'language' => 'en', + ); + $account = (object) $edit; + $_SESSION['entity_crud_hook_test'] = array(); + $account = user_save($account, $edit); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_insert called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $account = user_load($account->uid); + + $this->assertHookMessage('entity_crud_hook_test_entity_load called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_load called'); + + $_SESSION['entity_crud_hook_test'] = array(); + $edit['name'] = 'New name'; + $account = user_save($account, $edit); + + $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_presave called'); + $this->assertHookMessage('entity_crud_hook_test_entity_update called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_update called'); + + $_SESSION['entity_crud_hook_test'] = array(); + user_delete($account->uid); + + $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type user'); + $this->assertHookMessage('entity_crud_hook_test_user_delete called'); + } + +} diff --git modules/entity/tests/entity_query.test modules/entity/tests/entity_query.test new file mode 100644 index 0000000..4a319d7 --- /dev/null +++ modules/entity/tests/entity_query.test @@ -0,0 +1,1372 @@ + 'Entity query', + 'description' => 'Test the EntityFieldQuery class.', + 'group' => 'Entity API', + ); + } + + function setUp() { + parent::setUp(array('field_test')); + + field_attach_create_bundle('test_entity_bundle_key', 'bundle1'); + field_attach_create_bundle('test_entity_bundle_key', 'bundle2'); + field_attach_create_bundle('test_entity', 'test_bundles'); + field_attach_create_bundle('test_entity_bundle', 'test_entity_bundle'); + + $instances = array(); + $this->fields = array(); + $this->field_names[0] = $field_name = drupal_strtolower($this->randomName() . '_field_name'); + $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 4); + $field = field_create_field($field); + $this->fields[0] = $field; + $instance = array( + 'field_name' => $field_name, + 'entity_type' => '', + 'bundle' => '', + 'label' => $this->randomName() . '_label', + 'description' => $this->randomName() . '_description', + 'weight' => mt_rand(0, 127), + 'settings' => array( + 'test_instance_setting' => $this->randomName(), + ), + 'widget' => array( + 'type' => 'test_field_widget', + 'label' => 'Test Field', + 'settings' => array( + 'test_widget_setting' => $this->randomName(), + ) + ) + ); + + $instances[0] = $instance; + + // Add an instance to that bundle. + $instances[0]['bundle'] = 'bundle1'; + $instances[0]['entity_type'] = 'test_entity_bundle_key'; + field_create_instance($instances[0]); + $instances[0]['bundle'] = 'bundle2'; + field_create_instance($instances[0]); + $instances[0]['bundle'] = $instances[0]['entity_type'] = 'test_entity_bundle'; + field_create_instance($instances[0]); + + $this->field_names[1] = $field_name = drupal_strtolower($this->randomName() . '_field_name'); + $field = array('field_name' => $field_name, 'type' => 'shape', 'cardinality' => 4); + $field = field_create_field($field); + $this->fields[1] = $field; + $instance = array( + 'field_name' => $field_name, + 'entity_type' => '', + 'bundle' => '', + 'label' => $this->randomName() . '_label', + 'description' => $this->randomName() . '_description', + 'weight' => mt_rand(0, 127), + 'settings' => array( + 'test_instance_setting' => $this->randomName(), + ), + 'widget' => array( + 'type' => 'test_field_widget', + 'label' => 'Test Field', + 'settings' => array( + 'test_widget_setting' => $this->randomName(), + ) + ) + ); + + $instances[1] = $instance; + + // Add a field instance to the bundles. + $instances[1]['bundle'] = 'bundle1'; + $instances[1]['entity_type'] = 'test_entity_bundle_key'; + field_create_instance($instances[1]); + $instances[1]['bundle'] = $instances[1]['entity_type'] = 'test_entity_bundle'; + field_create_instance($instances[1]); + + $this->instances = $instances; + // Write entity base table if there is one. + $entities = array(); + + // Create entities which have a 'bundle key' defined. + for ($i = 1; $i < 7; $i++) { + $entity = new stdClass(); + $entity->ftid = $i; + $entity->fttype = ($i < 5) ? 'bundle1' : 'bundle2'; + + $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; + drupal_write_record('test_entity_bundle_key', $entity); + field_attach_insert('test_entity_bundle_key', $entity); + } + + $entity = new stdClass(); + $entity->ftid = 5; + $entity->fttype = 'test_entity_bundle'; + $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['shape'] = 'square'; + $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['color'] = 'red'; + $entity->{$this->field_names[1]}[LANGUAGE_NONE][1]['shape'] = 'circle'; + $entity->{$this->field_names[1]}[LANGUAGE_NONE][1]['color'] = 'blue'; + drupal_write_record('test_entity_bundle', $entity); + field_attach_insert('test_entity_bundle', $entity); + + $instances[2] = $instance; + $instances[2]['bundle'] = 'test_bundle'; + $instances[2]['field_name'] = $this->field_names[0]; + $instances[2]['entity_type'] = 'test_entity'; + field_create_instance($instances[2]); + + // Create entities with support for revisions. + for ($i = 1; $i < 5; $i++) { + $entity = new stdClass(); + $entity->ftid = $i; + $entity->ftvid = $i; + $entity->fttype = 'test_bundle'; + $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; + + drupal_write_record('test_entity', $entity); + field_attach_insert('test_entity', $entity); + drupal_write_record('test_entity_revision', $entity); + } + + // Add two revisions to an entity. + for ($i = 100; $i < 102; $i++) { + $entity = new stdClass(); + $entity->ftid = 4; + $entity->ftvid = $i; + $entity->fttype = 'test_bundle'; + $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; + + drupal_write_record('test_entity', $entity, 'ftid'); + drupal_write_record('test_entity_revision', $entity); + + db_update('test_entity') + ->fields(array('ftvid' => $entity->ftvid)) + ->condition('ftid', $entity->ftid) + ->execute(); + + field_attach_update('test_entity', $entity); + } + } + + /** + * Tests EntityFieldQuery. + */ + function testEntityFieldQuery() { + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle') + ->entityCondition('entity_id', '5'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 5), + ), t('Test query on an entity type with a generated bundle.')); + + // Test entity_type condition. + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', 'test_entity_bundle_key'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test entity entity_type condition.')); + + // Test entity_id condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityCondition('entity_id', '3'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + ), t('Test entity entity_id condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', '3'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + ), t('Test entity entity_id condition and entity_id property condition.')); + + // Test bundle condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityCondition('bundle', 'bundle1'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test entity bundle condition: bundle1.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityCondition('bundle', 'bundle2'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test entity bundle condition: bundle2.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('fttype', 'bundle2'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test entity bundle condition and bundle property condition.')); + + // Test revision_id condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->entityCondition('revision_id', '3'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 3), + ), t('Test entity revision_id condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->propertyCondition('ftvid', '3'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 3), + ), t('Test entity revision_id condition and revision_id property condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->fieldCondition($this->fields[0], 'value', 100, '>=') + ->age(FIELD_LOAD_REVISION); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 100), + array('test_entity', 101), + ), t('Test revision age.')); + + // Test that fields attached to the non-revision supporting entity + // 'test_entity_bundle_key' are reachable in FIELD_LOAD_REVISION. + $query = new EntityFieldQuery(); + $query + ->fieldCondition($this->fields[0], 'value', 100, '<') + ->age(FIELD_LOAD_REVISION); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test that fields are reachable from FIELD_LOAD_REVISION even for non-revision entities.')); + + // Test entity sort by entity_id. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('entity_id', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort entity entity_id in ascending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('entity_id', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort entity entity_id in descending order.'), TRUE); + + // Test entity sort by entity_id, with a field condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->entityOrderBy('entity_id', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort entity entity_id in ascending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort entity entity_id property in descending order, with a field condition.'), TRUE); + + // Test property sort by entity id. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort entity entity_id property in ascending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort entity entity_id property in descending order.'), TRUE); + + // Test property sort by entity id, with a field condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort entity entity_id property in ascending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort entity entity_id property in descending order, with a field condition.'), TRUE); + + // Test entity sort by bundle. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('bundle', 'ASC') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + ), t('Test sort entity bundle in ascending order, property in descending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('bundle', 'DESC') + ->propertyOrderBy('ftid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test sort entity bundle in descending order, property in ascending order.'), TRUE); + + // Test entity sort by bundle, with a field condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->entityOrderBy('bundle', 'ASC') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + ), t('Test sort entity bundle in ascending order, property in descending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->entityOrderBy('bundle', 'DESC') + ->propertyOrderBy('ftid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test sort entity bundle in descending order, property in ascending order, with a field condition.'), TRUE); + + // Test entity sort by bundle, field. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('bundle', 'ASC') + ->fieldOrderBy($this->fields[0], 'value', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + ), t('Test sort entity bundle in ascending order, field in descending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityOrderBy('bundle', 'DESC') + ->fieldOrderBy($this->fields[0], 'value', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test sort entity bundle in descending order, field in ascending order.'), TRUE); + + // Test entity sort by revision_id. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->entityOrderBy('revision_id', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test sort entity revision_id in ascending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->entityOrderBy('revision_id', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 4), + array('test_entity', 3), + array('test_entity', 2), + array('test_entity', 1), + ), t('Test sort entity revision_id in descending order.'), TRUE); + + // Test entity sort by revision_id, with a field condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->entityOrderBy('revision_id', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test sort entity revision_id in ascending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->entityOrderBy('revision_id', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 4), + array('test_entity', 3), + array('test_entity', 2), + array('test_entity', 1), + ), t('Test sort entity revision_id in descending order, with a field condition.'), TRUE); + + // Test property sort by revision_id. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->propertyOrderBy('ftvid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test sort entity revision_id property in ascending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->propertyOrderBy('ftvid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 4), + array('test_entity', 3), + array('test_entity', 2), + array('test_entity', 1), + ), t('Test sort entity revision_id property in descending order.'), TRUE); + + // Test property sort by revision_id, with a field condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftvid', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test sort entity revision_id property in ascending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftvid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 4), + array('test_entity', 3), + array('test_entity', 2), + array('test_entity', 1), + ), t('Test sort entity revision_id property in descending order, with a field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldOrderBy($this->fields[0], 'value', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort field in ascending order without field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldOrderBy($this->fields[0], 'value', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort field in descending order without field condition.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->fieldOrderBy($this->fields[0], 'value', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test sort field in ascending order.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->fieldOrderBy($this->fields[0], 'value', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test sort field in descending order.'), TRUE); + + // Test "in" operation with entity entity_type condition and entity_id + // property condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', array(1, 3, 4), 'IN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test "in" operation with entity entity_type condition and entity_id property condition.')); + + // Test "in" operation with entity entity_type condition and entity_id + // property condition. Sort in descending order by entity_id. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', array(1, 3, 4), 'IN') + ->propertyOrderBy('ftid', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 1), + ), t('Test "in" operation with entity entity_type condition and entity_id property condition. Sort entity_id in descending order.'), TRUE); + + // Test query count + $query = new EntityFieldQuery(); + $query_count = $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->count() + ->execute(); + $this->assertEqual($query_count, 6, t('Test query count on entity condition.')); + + $query = new EntityFieldQuery(); + $query_count = $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', '1') + ->count() + ->execute(); + $this->assertEqual($query_count, 1, t('Test query count on entity and property condition.')); + + $query = new EntityFieldQuery(); + $query_count = $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', '4', '>') + ->count() + ->execute(); + $this->assertEqual($query_count, 2, t('Test query count on entity and property condition with operator.')); + + $query = new EntityFieldQuery(); + $query_count = $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 3, '=') + ->count() + ->execute(); + $this->assertEqual($query_count, 1, t('Test query count on field condition.')); + + // First, test without options. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('fttype', 'und', 'CONTAINS'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "contains" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[1], 'shape', 'uar', 'CONTAINS'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 5), + ), t('Test the "contains" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 1, '='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + ), t('Test the "equal to" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 3, '='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity', 3), + ), t('Test the "equal to" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 3, '!='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "not equal to" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 3, '!='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 4), + ), t('Test the "not equal to" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 2, '<'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + ), t('Test the "less than" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 2, '<'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity', 1), + ), t('Test the "less than" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 2, '<='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + ), t('Test the "less than or equal to" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 2, '<='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity', 1), + array('test_entity', 2), + ), t('Test the "less than or equal to" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 4, '>'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "greater than" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 2, '>'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test the "greater than" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 4, '>='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "greater than or equal to" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 3, '>='); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 3), + array('test_entity', 4), + ), t('Test the "greater than or equal to" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', array(3, 4), 'NOT IN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "not in" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', array(3, 4, 100, 101), 'NOT IN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 1), + array('test_entity', 2), + ), t('Test the "not in" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', array(3, 4), 'IN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test the "in" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', array(2, 3), 'IN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity', 2), + array('test_entity', 3), + ), t('Test the "in" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', array(1, 3), 'BETWEEN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + ), t('Test the "between" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', array(1, 3), 'BETWEEN'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity', 1), + array('test_entity', 2), + array('test_entity', 3), + ), t('Test the "between" operation on a field.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('fttype', 'bun', 'STARTS_WITH'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test the "starts_with" operation on a property.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[1], 'shape', 'squ', 'STARTS_WITH'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 5), + ), t('Test the "starts_with" operation on a field.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 3); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity', 3), + ), t('Test omission of an operator with a single item.')); + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', array(2, 3)); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity', 2), + array('test_entity', 3), + ), t('Test omission of an operator with multiple items.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyCondition('ftid', 1, '>') + ->fieldCondition($this->fields[0], 'value', 4, '<'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + ), t('Test entity, property and field conditions.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->entityCondition('bundle', 'bundle', 'STARTS_WITH') + ->propertyCondition('ftid', 4) + ->fieldCondition($this->fields[0], 'value', 4); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + ), t('Test entity condition with "starts_with" operation, and property and field conditions.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'ASC') + ->range(0, 2); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + ), t('Test limit on a property.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>=') + ->fieldOrderBy($this->fields[0], 'value', 'ASC') + ->range(0, 2); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + ), t('Test limit on a field.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'ASC') + ->range(4, 6); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test offset on a property.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->fieldOrderBy($this->fields[0], 'value', 'ASC') + ->range(2, 4); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test offset on a field.'), TRUE); + + for ($i = 6; $i < 10; $i++) { + $entity = new stdClass(); + $entity->ftid = $i; + $entity->fttype = 'test_entity_bundle'; + $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i - 5; + drupal_write_record('test_entity_bundle', $entity); + field_attach_insert('test_entity_bundle', $entity); + } + + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', 2, '>'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity', 3), + array('test_entity', 4), + array('test_entity_bundle', 8), + array('test_entity_bundle', 9), + ), t('Select a field across multiple entities.')); + + $query = new EntityFieldQuery(); + $query + ->fieldCondition($this->fields[1], 'shape', 'square') + ->fieldCondition($this->fields[1], 'color', 'blue'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 5), + ), t('Test without a delta group.')); + + $query = new EntityFieldQuery(); + $query + ->fieldCondition($this->fields[1], 'shape', 'square', '=', 'group') + ->fieldCondition($this->fields[1], 'color', 'blue', '=', 'group'); + $this->assertEntityFieldQuery($query, array(), t('Test with a delta group.')); + + // Test query on a deleted field. + field_attach_delete_bundle('test_entity_bundle_key', 'bundle1'); + field_attach_delete_bundle('test_entity', 'test_bundle'); + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', '3'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 8), + ), t('Test query on a field after deleting field from some entities.')); + + field_attach_delete_bundle('test_entity_bundle', 'test_entity_bundle'); + $query = new EntityFieldQuery(); + $query->fieldCondition($this->fields[0], 'value', '3'); + $this->assertEntityFieldQuery($query, array(), t('Test query on a field after deleting field from all entities.')); + + $query = new EntityFieldQuery(); + $query + ->fieldCondition($this->fields[0], 'value', '3') + ->deleted(TRUE); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle', 8), + array('test_entity', 3), + ), t('Test query on a deleted field with deleted option set to TRUE.')); + + $pass = FALSE; + $query = new EntityFieldQuery(); + try { + $query->execute(); + } + catch (EntityFieldQueryException $exception) { + $pass = ($exception->getMessage() == t('For this query an entity type must be specified.')); + } + $this->assertTrue($pass, t("Can't query the universe.")); + } + + /** + * 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.')); + } + + /** + * Tests the pager integration of EntityFieldQuery. + */ + function testEntityFieldQueryPager() { + // Test pager in propertyQuery + $_GET['page'] = '0,1'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'ASC') + ->pager(3, 0); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + ), t('Test pager integration in propertyQuery: page 1.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->propertyOrderBy('ftid', 'ASC') + ->pager(3, 1); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test pager integration in propertyQuery: page 2.'), TRUE); + + // Test pager in field storage + $_GET['page'] = '0,1'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftid', 'ASC') + ->pager(2, 0); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + ), t('Test pager integration in field storage: page 1.'), TRUE); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->propertyOrderBy('ftid', 'ASC') + ->pager(2, 1); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test pager integration in field storage: page 2.'), TRUE); + + unset($_GET['page']); + } + + /** + * Tests the TableSort integration of EntityFieldQuery. + */ + function testEntityFieldQueryTableSort() { + // Test TableSort in propertyQuery + $_GET['sort'] = 'asc'; + $_GET['order'] = 'Id'; + $header = array( + 'id' => array('data' => 'Id', 'type' => 'property', 'specifier' => 'ftid'), + 'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'), + ); + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test TableSort by property: ftid ASC in propertyQuery.'), TRUE); + + $_GET['sort'] = 'desc'; + $_GET['order'] = 'Id'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test TableSort by property: ftid DESC in propertyQuery.'), TRUE); + + $_GET['sort'] = 'asc'; + $_GET['order'] = 'Type'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test TableSort by entity: bundle ASC in propertyQuery.'), TRUE); + + $_GET['sort'] = 'desc'; + $_GET['order'] = 'Type'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test TableSort by entity: bundle DESC in propertyQuery.'), TRUE); + + // Test TableSort in field storage + $_GET['sort'] = 'asc'; + $_GET['order'] = 'Id'; + $header = array( + 'id' => array('data' => 'Id', 'type' => 'property', 'specifier' => 'ftid'), + 'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'), + 'field' => array('data' => 'Field', 'type' => 'field', 'specifier' => array('field' => $this->field_names[0], 'column' => 'value')), + ); + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test TableSort by property: ftid ASC in field storage.'), TRUE); + + $_GET['sort'] = 'desc'; + $_GET['order'] = 'Id'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test TableSort by property: ftid DESC in field storage.'), TRUE); + + $_GET['sort'] = 'asc'; + $_GET['order'] = 'Type'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header) + ->entityOrderBy('entity_id', 'DESC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + ), t('Test TableSort by entity: bundle ASC in field storage.'), TRUE); + + $_GET['sort'] = 'desc'; + $_GET['order'] = 'Type'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header) + ->entityOrderBy('entity_id', 'ASC'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + ), t('Test TableSort by entity: bundle DESC in field storage.'), TRUE); + + $_GET['sort'] = 'asc'; + $_GET['order'] = 'Field'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 1), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 6), + ), t('Test TableSort by field ASC.'), TRUE); + + $_GET['sort'] = 'desc'; + $_GET['order'] = 'Field'; + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle_key') + ->fieldCondition($this->fields[0], 'value', 0, '>') + ->tableSort($header); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle_key', 6), + array('test_entity_bundle_key', 5), + array('test_entity_bundle_key', 4), + array('test_entity_bundle_key', 3), + array('test_entity_bundle_key', 2), + array('test_entity_bundle_key', 1), + ), t('Test TableSort by field DESC.'), TRUE); + + unset($_GET['sort']); + unset($_GET['order']); + } + + /** + * Fetches the results of an EntityFieldQuery and compares. + * + * @param $query + * An EntityFieldQuery to run. + * @param $intended_results + * A list of results, every entry is again a list, first being the entity + * type, the second being the entity_id. + * @param $message + * The message to be displayed as the result of this test. + * @param $ordered + * If FALSE then the result of EntityFieldQuery will match + * $intended_results even if the order is not the same. If TRUE then order + * should match too. + */ + function assertEntityFieldQuery($query, $intended_results, $message, $ordered = FALSE) { + $results = array(); + try { + foreach ($query->execute() as $entity_type => $entity_ids) { + foreach ($entity_ids as $entity_id => $stub_entity) { + $results[] = array($entity_type, $entity_id); + } + } + if (!isset($ordered) || !$ordered) { + sort($results); + sort($intended_results); + } + $this->assertEqual($results, $intended_results, $message); + } + catch (Exception $e) { + $this->fail('Exception thrown: '. $e->getMessage()); + } + } +} diff --git modules/field/field.info modules/field/field.info index 3a1b20d..49011ff 100644 --- modules/field/field.info +++ modules/field/field.info @@ -7,6 +7,6 @@ core = 7.x files[] = field.module files[] = field.attach.inc files[] = tests/field.test -dependencies[] = field_sql_storage +dependencies[] = field_sql_storage entity required = TRUE stylesheets[all][] = theme/field.css diff --git modules/simpletest/tests/entity_cache_test.info modules/simpletest/tests/entity_cache_test.info deleted file mode 100644 index 01c6d5d..0000000 --- modules/simpletest/tests/entity_cache_test.info +++ /dev/null @@ -1,8 +0,0 @@ -; $Id$ -name = "Entity cache test" -description = "Support module for testing entity cache." -package = Testing -version = VERSION -core = 7.x -dependencies[] = entity_cache_test_dependency -hidden = TRUE diff --git modules/simpletest/tests/entity_cache_test.module modules/simpletest/tests/entity_cache_test.module deleted file mode 100644 index b1daf68..0000000 --- modules/simpletest/tests/entity_cache_test.module +++ /dev/null @@ -1,28 +0,0 @@ - array( - 'label' => 'Entity Cache Test', - ), - ); -} diff --git modules/simpletest/tests/entity_crud_hook_test.info modules/simpletest/tests/entity_crud_hook_test.info deleted file mode 100644 index 5cc2ad9..0000000 --- modules/simpletest/tests/entity_crud_hook_test.info +++ /dev/null @@ -1,7 +0,0 @@ -; $Id$ -name = "Entity CRUD Hooks Test" -description = "Support module for CRUD hook tests." -core = 7.x -package = Testing -version = VERSION -hidden = TRUE diff --git modules/simpletest/tests/entity_crud_hook_test.module modules/simpletest/tests/entity_crud_hook_test.module deleted file mode 100644 index 12252d1..0000000 --- modules/simpletest/tests/entity_crud_hook_test.module +++ /dev/null @@ -1,267 +0,0 @@ - 'Entity CRUD hooks', - 'description' => 'Tests the invocation of hooks when inserting, loading, updating or deleting an entity.', - 'group' => 'Entity API', - ); - } - - public function setUp() { - parent::setUp('entity_crud_hook_test', 'taxonomy', 'comment'); - } - - /** - * Pass if the message $text was set by one of the CRUD hooks in - * entity_crud_hook_test.module, i.e., if the $text is an element of - * $_SESSION['entity_crud_hook_test']. - * - * @param $text - * Plain text to look for. - * @param $message - * Message to display. - * @param $group - * The group this message belongs to, defaults to 'Other'. - * @return - * TRUE on pass, FALSE on fail. - */ - protected function assertHookMessage($text, $message = NULL, $group = 'Other') { - if (!isset($message)) { - $message = $text; - } - return $this->assertTrue(array_search($text, $_SESSION['entity_crud_hook_test']) !== FALSE, $message, $group); - } - - /** - * Test hook invocations for CRUD operations on comments. - */ - public function testCommentHooks() { - $node = (object) array( - 'uid' => 1, - 'type' => 'article', - 'title' => 'Test node', - 'status' => 1, - 'comment' => 2, - 'promote' => 0, - 'sticky' => 0, - 'language' => LANGUAGE_NONE, - 'created' => REQUEST_TIME, - 'changed' => REQUEST_TIME, - ); - node_save($node); - $nid = $node->nid; - - $comment = (object) array( - 'cid' => NULL, - 'pid' => 0, - 'nid' => $nid, - 'uid' => 1, - 'subject' => 'Test comment', - 'created' => REQUEST_TIME, - 'changed' => REQUEST_TIME, - 'status' => 1, - 'language' => LANGUAGE_NONE, - ); - $_SESSION['entity_crud_hook_test'] = array(); - comment_save($comment); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $comment = comment_load($comment->cid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $comment->subject = 'New subject'; - comment_save($comment); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - comment_delete($comment->cid); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type comment'); - $this->assertHookMessage('entity_crud_hook_test_comment_delete called'); - } - - /** - * Test hook invocations for CRUD operations on files. - */ - public function testFileHooks() { - $url = 'public://entity_crud_hook_test.file'; - file_put_contents($url, 'Test test test'); - $file = (object) array( - 'fid' => NULL, - 'uid' => 1, - 'filename' => 'entity_crud_hook_test.file', - 'uri' => $url, - 'filemime' => 'text/plain', - 'filesize' => filesize($url), - 'status' => 1, - 'timestamp' => REQUEST_TIME, - ); - $_SESSION['entity_crud_hook_test'] = array(); - file_save($file); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $file = file_load($file->fid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $file->filename = 'new.entity_crud_hook_test.file'; - file_save($file); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - file_delete($file); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type file'); - $this->assertHookMessage('entity_crud_hook_test_file_delete called'); - } - - /** - * Test hook invocations for CRUD operations on nodes. - */ - public function testNodeHooks() { - $node = (object) array( - 'uid' => 1, - 'type' => 'article', - 'title' => 'Test node', - 'status' => 1, - 'comment' => 2, - 'promote' => 0, - 'sticky' => 0, - 'language' => LANGUAGE_NONE, - 'created' => REQUEST_TIME, - 'changed' => REQUEST_TIME, - ); - $_SESSION['entity_crud_hook_test'] = array(); - node_save($node); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $node = node_load($node->nid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $node->title = 'New title'; - node_save($node); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - node_delete($node->nid); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type node'); - $this->assertHookMessage('entity_crud_hook_test_node_delete called'); - } - - /** - * Test hook invocations for CRUD operations on taxonomy terms. - */ - public function testTaxonomyTermHooks() { - $vocabulary = (object) array( - 'name' => 'Test vocabulary', - 'machine_name' => 'test', - 'description' => NULL, - 'module' => 'entity_crud_hook_test', - ); - taxonomy_vocabulary_save($vocabulary); - - $term = (object) array( - 'vid' => $vocabulary->vid, - 'name' => 'Test term', - 'description' => NULL, - 'format' => 1, - ); - $_SESSION['entity_crud_hook_test'] = array(); - taxonomy_term_save($term); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $term = taxonomy_term_load($term->tid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $term->name = 'New name'; - taxonomy_term_save($term); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - taxonomy_term_delete($term->tid); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_term'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_term_delete called'); - } - - /** - * Test hook invocations for CRUD operations on taxonomy vocabularies. - */ - public function testTaxonomyVocabularyHooks() { - $vocabulary = (object) array( - 'name' => 'Test vocabulary', - 'machine_name' => 'test', - 'description' => NULL, - 'module' => 'entity_crud_hook_test', - ); - $_SESSION['entity_crud_hook_test'] = array(); - taxonomy_vocabulary_save($vocabulary); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $vocabulary = taxonomy_vocabulary_load($vocabulary->vid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $vocabulary->name = 'New name'; - taxonomy_vocabulary_save($vocabulary); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - taxonomy_vocabulary_delete($vocabulary->vid); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary'); - $this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_delete called'); - } - - /** - * Test hook invocations for CRUD operations on users. - */ - public function testUserHooks() { - $edit = array( - 'name' => 'Test user', - 'mail' => 'test@example.com', - 'created' => REQUEST_TIME, - 'status' => 1, - 'language' => 'en', - ); - $account = (object) $edit; - $_SESSION['entity_crud_hook_test'] = array(); - $account = user_save($account, $edit); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_insert called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_insert called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $account = user_load($account->uid); - - $this->assertHookMessage('entity_crud_hook_test_entity_load called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_load called'); - - $_SESSION['entity_crud_hook_test'] = array(); - $edit['name'] = 'New name'; - $account = user_save($account, $edit); - - $this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_presave called'); - $this->assertHookMessage('entity_crud_hook_test_entity_update called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_update called'); - - $_SESSION['entity_crud_hook_test'] = array(); - user_delete($account->uid); - - $this->assertHookMessage('entity_crud_hook_test_entity_delete called for type user'); - $this->assertHookMessage('entity_crud_hook_test_user_delete called'); - } - -} diff --git modules/simpletest/tests/entity_query.test modules/simpletest/tests/entity_query.test deleted file mode 100644 index 4a319d7..0000000 --- modules/simpletest/tests/entity_query.test +++ /dev/null @@ -1,1372 +0,0 @@ - 'Entity query', - 'description' => 'Test the EntityFieldQuery class.', - 'group' => 'Entity API', - ); - } - - function setUp() { - parent::setUp(array('field_test')); - - field_attach_create_bundle('test_entity_bundle_key', 'bundle1'); - field_attach_create_bundle('test_entity_bundle_key', 'bundle2'); - field_attach_create_bundle('test_entity', 'test_bundles'); - field_attach_create_bundle('test_entity_bundle', 'test_entity_bundle'); - - $instances = array(); - $this->fields = array(); - $this->field_names[0] = $field_name = drupal_strtolower($this->randomName() . '_field_name'); - $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 4); - $field = field_create_field($field); - $this->fields[0] = $field; - $instance = array( - 'field_name' => $field_name, - 'entity_type' => '', - 'bundle' => '', - 'label' => $this->randomName() . '_label', - 'description' => $this->randomName() . '_description', - 'weight' => mt_rand(0, 127), - 'settings' => array( - 'test_instance_setting' => $this->randomName(), - ), - 'widget' => array( - 'type' => 'test_field_widget', - 'label' => 'Test Field', - 'settings' => array( - 'test_widget_setting' => $this->randomName(), - ) - ) - ); - - $instances[0] = $instance; - - // Add an instance to that bundle. - $instances[0]['bundle'] = 'bundle1'; - $instances[0]['entity_type'] = 'test_entity_bundle_key'; - field_create_instance($instances[0]); - $instances[0]['bundle'] = 'bundle2'; - field_create_instance($instances[0]); - $instances[0]['bundle'] = $instances[0]['entity_type'] = 'test_entity_bundle'; - field_create_instance($instances[0]); - - $this->field_names[1] = $field_name = drupal_strtolower($this->randomName() . '_field_name'); - $field = array('field_name' => $field_name, 'type' => 'shape', 'cardinality' => 4); - $field = field_create_field($field); - $this->fields[1] = $field; - $instance = array( - 'field_name' => $field_name, - 'entity_type' => '', - 'bundle' => '', - 'label' => $this->randomName() . '_label', - 'description' => $this->randomName() . '_description', - 'weight' => mt_rand(0, 127), - 'settings' => array( - 'test_instance_setting' => $this->randomName(), - ), - 'widget' => array( - 'type' => 'test_field_widget', - 'label' => 'Test Field', - 'settings' => array( - 'test_widget_setting' => $this->randomName(), - ) - ) - ); - - $instances[1] = $instance; - - // Add a field instance to the bundles. - $instances[1]['bundle'] = 'bundle1'; - $instances[1]['entity_type'] = 'test_entity_bundle_key'; - field_create_instance($instances[1]); - $instances[1]['bundle'] = $instances[1]['entity_type'] = 'test_entity_bundle'; - field_create_instance($instances[1]); - - $this->instances = $instances; - // Write entity base table if there is one. - $entities = array(); - - // Create entities which have a 'bundle key' defined. - for ($i = 1; $i < 7; $i++) { - $entity = new stdClass(); - $entity->ftid = $i; - $entity->fttype = ($i < 5) ? 'bundle1' : 'bundle2'; - - $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; - drupal_write_record('test_entity_bundle_key', $entity); - field_attach_insert('test_entity_bundle_key', $entity); - } - - $entity = new stdClass(); - $entity->ftid = 5; - $entity->fttype = 'test_entity_bundle'; - $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['shape'] = 'square'; - $entity->{$this->field_names[1]}[LANGUAGE_NONE][0]['color'] = 'red'; - $entity->{$this->field_names[1]}[LANGUAGE_NONE][1]['shape'] = 'circle'; - $entity->{$this->field_names[1]}[LANGUAGE_NONE][1]['color'] = 'blue'; - drupal_write_record('test_entity_bundle', $entity); - field_attach_insert('test_entity_bundle', $entity); - - $instances[2] = $instance; - $instances[2]['bundle'] = 'test_bundle'; - $instances[2]['field_name'] = $this->field_names[0]; - $instances[2]['entity_type'] = 'test_entity'; - field_create_instance($instances[2]); - - // Create entities with support for revisions. - for ($i = 1; $i < 5; $i++) { - $entity = new stdClass(); - $entity->ftid = $i; - $entity->ftvid = $i; - $entity->fttype = 'test_bundle'; - $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; - - drupal_write_record('test_entity', $entity); - field_attach_insert('test_entity', $entity); - drupal_write_record('test_entity_revision', $entity); - } - - // Add two revisions to an entity. - for ($i = 100; $i < 102; $i++) { - $entity = new stdClass(); - $entity->ftid = 4; - $entity->ftvid = $i; - $entity->fttype = 'test_bundle'; - $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i; - - drupal_write_record('test_entity', $entity, 'ftid'); - drupal_write_record('test_entity_revision', $entity); - - db_update('test_entity') - ->fields(array('ftvid' => $entity->ftvid)) - ->condition('ftid', $entity->ftid) - ->execute(); - - field_attach_update('test_entity', $entity); - } - } - - /** - * Tests EntityFieldQuery. - */ - function testEntityFieldQuery() { - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle') - ->entityCondition('entity_id', '5'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle', 5), - ), t('Test query on an entity type with a generated bundle.')); - - // Test entity_type condition. - $query = new EntityFieldQuery(); - $query->entityCondition('entity_type', 'test_entity_bundle_key'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test entity entity_type condition.')); - - // Test entity_id condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityCondition('entity_id', '3'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - ), t('Test entity entity_id condition.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', '3'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - ), t('Test entity entity_id condition and entity_id property condition.')); - - // Test bundle condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityCondition('bundle', 'bundle1'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test entity bundle condition: bundle1.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityCondition('bundle', 'bundle2'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test entity bundle condition: bundle2.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('fttype', 'bundle2'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test entity bundle condition and bundle property condition.')); - - // Test revision_id condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->entityCondition('revision_id', '3'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 3), - ), t('Test entity revision_id condition.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->propertyCondition('ftvid', '3'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 3), - ), t('Test entity revision_id condition and revision_id property condition.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->fieldCondition($this->fields[0], 'value', 100, '>=') - ->age(FIELD_LOAD_REVISION); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 100), - array('test_entity', 101), - ), t('Test revision age.')); - - // Test that fields attached to the non-revision supporting entity - // 'test_entity_bundle_key' are reachable in FIELD_LOAD_REVISION. - $query = new EntityFieldQuery(); - $query - ->fieldCondition($this->fields[0], 'value', 100, '<') - ->age(FIELD_LOAD_REVISION); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test that fields are reachable from FIELD_LOAD_REVISION even for non-revision entities.')); - - // Test entity sort by entity_id. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('entity_id', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort entity entity_id in ascending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('entity_id', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort entity entity_id in descending order.'), TRUE); - - // Test entity sort by entity_id, with a field condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->entityOrderBy('entity_id', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort entity entity_id in ascending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort entity entity_id property in descending order, with a field condition.'), TRUE); - - // Test property sort by entity id. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort entity entity_id property in ascending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort entity entity_id property in descending order.'), TRUE); - - // Test property sort by entity id, with a field condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort entity entity_id property in ascending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort entity entity_id property in descending order, with a field condition.'), TRUE); - - // Test entity sort by bundle. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('bundle', 'ASC') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - ), t('Test sort entity bundle in ascending order, property in descending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('bundle', 'DESC') - ->propertyOrderBy('ftid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test sort entity bundle in descending order, property in ascending order.'), TRUE); - - // Test entity sort by bundle, with a field condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->entityOrderBy('bundle', 'ASC') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - ), t('Test sort entity bundle in ascending order, property in descending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->entityOrderBy('bundle', 'DESC') - ->propertyOrderBy('ftid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test sort entity bundle in descending order, property in ascending order, with a field condition.'), TRUE); - - // Test entity sort by bundle, field. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('bundle', 'ASC') - ->fieldOrderBy($this->fields[0], 'value', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - ), t('Test sort entity bundle in ascending order, field in descending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityOrderBy('bundle', 'DESC') - ->fieldOrderBy($this->fields[0], 'value', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test sort entity bundle in descending order, field in ascending order.'), TRUE); - - // Test entity sort by revision_id. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->entityOrderBy('revision_id', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test sort entity revision_id in ascending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->entityOrderBy('revision_id', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 4), - array('test_entity', 3), - array('test_entity', 2), - array('test_entity', 1), - ), t('Test sort entity revision_id in descending order.'), TRUE); - - // Test entity sort by revision_id, with a field condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->entityOrderBy('revision_id', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test sort entity revision_id in ascending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->entityOrderBy('revision_id', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 4), - array('test_entity', 3), - array('test_entity', 2), - array('test_entity', 1), - ), t('Test sort entity revision_id in descending order, with a field condition.'), TRUE); - - // Test property sort by revision_id. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->propertyOrderBy('ftvid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test sort entity revision_id property in ascending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->propertyOrderBy('ftvid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 4), - array('test_entity', 3), - array('test_entity', 2), - array('test_entity', 1), - ), t('Test sort entity revision_id property in descending order.'), TRUE); - - // Test property sort by revision_id, with a field condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftvid', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test sort entity revision_id property in ascending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftvid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity', 4), - array('test_entity', 3), - array('test_entity', 2), - array('test_entity', 1), - ), t('Test sort entity revision_id property in descending order, with a field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldOrderBy($this->fields[0], 'value', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort field in ascending order without field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldOrderBy($this->fields[0], 'value', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort field in descending order without field condition.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->fieldOrderBy($this->fields[0], 'value', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test sort field in ascending order.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->fieldOrderBy($this->fields[0], 'value', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test sort field in descending order.'), TRUE); - - // Test "in" operation with entity entity_type condition and entity_id - // property condition. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', array(1, 3, 4), 'IN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test "in" operation with entity entity_type condition and entity_id property condition.')); - - // Test "in" operation with entity entity_type condition and entity_id - // property condition. Sort in descending order by entity_id. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', array(1, 3, 4), 'IN') - ->propertyOrderBy('ftid', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 1), - ), t('Test "in" operation with entity entity_type condition and entity_id property condition. Sort entity_id in descending order.'), TRUE); - - // Test query count - $query = new EntityFieldQuery(); - $query_count = $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->count() - ->execute(); - $this->assertEqual($query_count, 6, t('Test query count on entity condition.')); - - $query = new EntityFieldQuery(); - $query_count = $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', '1') - ->count() - ->execute(); - $this->assertEqual($query_count, 1, t('Test query count on entity and property condition.')); - - $query = new EntityFieldQuery(); - $query_count = $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', '4', '>') - ->count() - ->execute(); - $this->assertEqual($query_count, 2, t('Test query count on entity and property condition with operator.')); - - $query = new EntityFieldQuery(); - $query_count = $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 3, '=') - ->count() - ->execute(); - $this->assertEqual($query_count, 1, t('Test query count on field condition.')); - - // First, test without options. - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('fttype', 'und', 'CONTAINS'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "contains" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[1], 'shape', 'uar', 'CONTAINS'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle', 5), - ), t('Test the "contains" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 1, '='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - ), t('Test the "equal to" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 3, '='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity', 3), - ), t('Test the "equal to" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 3, '!='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "not equal to" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 3, '!='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 4), - ), t('Test the "not equal to" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 2, '<'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - ), t('Test the "less than" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 2, '<'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity', 1), - ), t('Test the "less than" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 2, '<='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - ), t('Test the "less than or equal to" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 2, '<='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity', 1), - array('test_entity', 2), - ), t('Test the "less than or equal to" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 4, '>'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "greater than" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 2, '>'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test the "greater than" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 4, '>='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "greater than or equal to" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 3, '>='); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 3), - array('test_entity', 4), - ), t('Test the "greater than or equal to" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', array(3, 4), 'NOT IN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "not in" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', array(3, 4, 100, 101), 'NOT IN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 1), - array('test_entity', 2), - ), t('Test the "not in" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', array(3, 4), 'IN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test the "in" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', array(2, 3), 'IN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity', 2), - array('test_entity', 3), - ), t('Test the "in" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', array(1, 3), 'BETWEEN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - ), t('Test the "between" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', array(1, 3), 'BETWEEN'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity', 1), - array('test_entity', 2), - array('test_entity', 3), - ), t('Test the "between" operation on a field.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('fttype', 'bun', 'STARTS_WITH'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test the "starts_with" operation on a property.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[1], 'shape', 'squ', 'STARTS_WITH'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle', 5), - ), t('Test the "starts_with" operation on a field.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 3); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity', 3), - ), t('Test omission of an operator with a single item.')); - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', array(2, 3)); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity', 2), - array('test_entity', 3), - ), t('Test omission of an operator with multiple items.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyCondition('ftid', 1, '>') - ->fieldCondition($this->fields[0], 'value', 4, '<'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - ), t('Test entity, property and field conditions.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->entityCondition('bundle', 'bundle', 'STARTS_WITH') - ->propertyCondition('ftid', 4) - ->fieldCondition($this->fields[0], 'value', 4); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - ), t('Test entity condition with "starts_with" operation, and property and field conditions.')); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'ASC') - ->range(0, 2); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - ), t('Test limit on a property.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>=') - ->fieldOrderBy($this->fields[0], 'value', 'ASC') - ->range(0, 2); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - ), t('Test limit on a field.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'ASC') - ->range(4, 6); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test offset on a property.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->fieldOrderBy($this->fields[0], 'value', 'ASC') - ->range(2, 4); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test offset on a field.'), TRUE); - - for ($i = 6; $i < 10; $i++) { - $entity = new stdClass(); - $entity->ftid = $i; - $entity->fttype = 'test_entity_bundle'; - $entity->{$this->field_names[0]}[LANGUAGE_NONE][0]['value'] = $i - 5; - drupal_write_record('test_entity_bundle', $entity); - field_attach_insert('test_entity_bundle', $entity); - } - - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', 2, '>'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity', 3), - array('test_entity', 4), - array('test_entity_bundle', 8), - array('test_entity_bundle', 9), - ), t('Select a field across multiple entities.')); - - $query = new EntityFieldQuery(); - $query - ->fieldCondition($this->fields[1], 'shape', 'square') - ->fieldCondition($this->fields[1], 'color', 'blue'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle', 5), - ), t('Test without a delta group.')); - - $query = new EntityFieldQuery(); - $query - ->fieldCondition($this->fields[1], 'shape', 'square', '=', 'group') - ->fieldCondition($this->fields[1], 'color', 'blue', '=', 'group'); - $this->assertEntityFieldQuery($query, array(), t('Test with a delta group.')); - - // Test query on a deleted field. - field_attach_delete_bundle('test_entity_bundle_key', 'bundle1'); - field_attach_delete_bundle('test_entity', 'test_bundle'); - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', '3'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle', 8), - ), t('Test query on a field after deleting field from some entities.')); - - field_attach_delete_bundle('test_entity_bundle', 'test_entity_bundle'); - $query = new EntityFieldQuery(); - $query->fieldCondition($this->fields[0], 'value', '3'); - $this->assertEntityFieldQuery($query, array(), t('Test query on a field after deleting field from all entities.')); - - $query = new EntityFieldQuery(); - $query - ->fieldCondition($this->fields[0], 'value', '3') - ->deleted(TRUE); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle', 8), - array('test_entity', 3), - ), t('Test query on a deleted field with deleted option set to TRUE.')); - - $pass = FALSE; - $query = new EntityFieldQuery(); - try { - $query->execute(); - } - catch (EntityFieldQueryException $exception) { - $pass = ($exception->getMessage() == t('For this query an entity type must be specified.')); - } - $this->assertTrue($pass, t("Can't query the universe.")); - } - - /** - * 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.')); - } - - /** - * Tests the pager integration of EntityFieldQuery. - */ - function testEntityFieldQueryPager() { - // Test pager in propertyQuery - $_GET['page'] = '0,1'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'ASC') - ->pager(3, 0); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - ), t('Test pager integration in propertyQuery: page 1.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->propertyOrderBy('ftid', 'ASC') - ->pager(3, 1); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test pager integration in propertyQuery: page 2.'), TRUE); - - // Test pager in field storage - $_GET['page'] = '0,1'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftid', 'ASC') - ->pager(2, 0); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - ), t('Test pager integration in field storage: page 1.'), TRUE); - - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->propertyOrderBy('ftid', 'ASC') - ->pager(2, 1); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test pager integration in field storage: page 2.'), TRUE); - - unset($_GET['page']); - } - - /** - * Tests the TableSort integration of EntityFieldQuery. - */ - function testEntityFieldQueryTableSort() { - // Test TableSort in propertyQuery - $_GET['sort'] = 'asc'; - $_GET['order'] = 'Id'; - $header = array( - 'id' => array('data' => 'Id', 'type' => 'property', 'specifier' => 'ftid'), - 'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'), - ); - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test TableSort by property: ftid ASC in propertyQuery.'), TRUE); - - $_GET['sort'] = 'desc'; - $_GET['order'] = 'Id'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test TableSort by property: ftid DESC in propertyQuery.'), TRUE); - - $_GET['sort'] = 'asc'; - $_GET['order'] = 'Type'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test TableSort by entity: bundle ASC in propertyQuery.'), TRUE); - - $_GET['sort'] = 'desc'; - $_GET['order'] = 'Type'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test TableSort by entity: bundle DESC in propertyQuery.'), TRUE); - - // Test TableSort in field storage - $_GET['sort'] = 'asc'; - $_GET['order'] = 'Id'; - $header = array( - 'id' => array('data' => 'Id', 'type' => 'property', 'specifier' => 'ftid'), - 'type' => array('data' => 'Type', 'type' => 'entity', 'specifier' => 'bundle'), - 'field' => array('data' => 'Field', 'type' => 'field', 'specifier' => array('field' => $this->field_names[0], 'column' => 'value')), - ); - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test TableSort by property: ftid ASC in field storage.'), TRUE); - - $_GET['sort'] = 'desc'; - $_GET['order'] = 'Id'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test TableSort by property: ftid DESC in field storage.'), TRUE); - - $_GET['sort'] = 'asc'; - $_GET['order'] = 'Type'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header) - ->entityOrderBy('entity_id', 'DESC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - ), t('Test TableSort by entity: bundle ASC in field storage.'), TRUE); - - $_GET['sort'] = 'desc'; - $_GET['order'] = 'Type'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header) - ->entityOrderBy('entity_id', 'ASC'); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - ), t('Test TableSort by entity: bundle DESC in field storage.'), TRUE); - - $_GET['sort'] = 'asc'; - $_GET['order'] = 'Field'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 1), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 6), - ), t('Test TableSort by field ASC.'), TRUE); - - $_GET['sort'] = 'desc'; - $_GET['order'] = 'Field'; - $query = new EntityFieldQuery(); - $query - ->entityCondition('entity_type', 'test_entity_bundle_key') - ->fieldCondition($this->fields[0], 'value', 0, '>') - ->tableSort($header); - $this->assertEntityFieldQuery($query, array( - array('test_entity_bundle_key', 6), - array('test_entity_bundle_key', 5), - array('test_entity_bundle_key', 4), - array('test_entity_bundle_key', 3), - array('test_entity_bundle_key', 2), - array('test_entity_bundle_key', 1), - ), t('Test TableSort by field DESC.'), TRUE); - - unset($_GET['sort']); - unset($_GET['order']); - } - - /** - * Fetches the results of an EntityFieldQuery and compares. - * - * @param $query - * An EntityFieldQuery to run. - * @param $intended_results - * A list of results, every entry is again a list, first being the entity - * type, the second being the entity_id. - * @param $message - * The message to be displayed as the result of this test. - * @param $ordered - * If FALSE then the result of EntityFieldQuery will match - * $intended_results even if the order is not the same. If TRUE then order - * should match too. - */ - function assertEntityFieldQuery($query, $intended_results, $message, $ordered = FALSE) { - $results = array(); - try { - foreach ($query->execute() as $entity_type => $entity_ids) { - foreach ($entity_ids as $entity_id => $stub_entity) { - $results[] = array($entity_type, $entity_id); - } - } - if (!isset($ordered) || !$ordered) { - sort($results); - sort($intended_results); - } - $this->assertEqual($results, $intended_results, $message); - } - catch (Exception $e) { - $this->fail('Exception thrown: '. $e->getMessage()); - } - } -}