#885014 by bojanz, chx: Fixed add missing pager and tablesort query support to EntityFieldQuery.
parent
4575c982a2
commit
0c33e86388
|
@ -418,6 +418,16 @@ class EntityFieldQuery {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -461,6 +471,15 @@ class EntityFieldQuery {
|
|||
*/
|
||||
public $range = array();
|
||||
|
||||
/**
|
||||
* The query pager data.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see EntityFieldQuery::pager()
|
||||
*/
|
||||
public $pager = array();
|
||||
|
||||
/**
|
||||
* Query behavior for deleted data.
|
||||
*
|
||||
|
@ -798,6 +817,68 @@ class EntityFieldQuery {
|
|||
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.
|
||||
*
|
||||
|
@ -911,6 +992,10 @@ class EntityFieldQuery {
|
|||
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);
|
||||
|
@ -966,7 +1051,6 @@ class EntityFieldQuery {
|
|||
throw new EntityFieldQueryException(t('For this query an entity type must be specified.'));
|
||||
}
|
||||
$entity_type = $this->entityConditions['entity_type']['value'];
|
||||
unset($this->entityConditions['entity_type']);
|
||||
$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)));
|
||||
|
@ -1038,6 +1122,24 @@ class EntityFieldQuery {
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -20,7 +20,7 @@ class PagerDefault extends SelectQueryExtender {
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
static protected $maxElement = 0;
|
||||
static $maxElement = 0;
|
||||
|
||||
/**
|
||||
* The number of elements per page to allow.
|
||||
|
|
|
@ -1104,6 +1104,238 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase {
|
|||
$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.
|
||||
*
|
||||
|
|
|
@ -350,6 +350,13 @@ function hook_entity_delete($entity, $type) {
|
|||
* engines. Also, the default implementation presumes entities are stored in
|
||||
* SQL, but the execute callback could instead query any other entity storage,
|
||||
* local or remote.
|
||||
*
|
||||
* Note the $query->altered attribute which is TRUE in case the query has
|
||||
* already been altered once. This happens with cloned queries.
|
||||
* If there is a pager, then such a cloned query will be executed to count
|
||||
* all elements. This query can be detected by checking for
|
||||
* ($query->pager && $query->count), allowing the driver to return 0 from
|
||||
* the count query and disable the pager.
|
||||
*/
|
||||
function hook_entity_query_alter($query) {
|
||||
$query->executeCallback = 'my_module_query_callback';
|
||||
|
|
Loading…
Reference in New Issue