aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Clay <steve@mrclay.org>2013-06-03 17:02:33 -0400
committerSteve Clay <steve@mrclay.org>2013-06-03 17:02:33 -0400
commit35acc4a297de7660a191d4e7f9d3e8d55561885a (patch)
tree10a9ab4e9fc067cde92948597ffbfdce673af57d
parent50dee6fe09a1f600089b1684f6f8f91599c365a1 (diff)
downloadelgg-35acc4a297de7660a191d4e7f9d3e8d55561885a.tar.gz
elgg-35acc4a297de7660a191d4e7f9d3e8d55561885a.tar.bz2
Refs #5357: Introduces ElggBatch awareness of incomplete entities during fetch
-rw-r--r--engine/classes/ElggBatch.php30
-rw-r--r--engine/lib/entities.php14
-rw-r--r--engine/tests/api/helpers.php48
3 files changed, 83 insertions, 9 deletions
diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index eb93b0f5d..34520f2bc 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -150,6 +150,13 @@ class ElggBatch
private $incrementOffset = true;
/**
+ * Entities that could not be instantiated during a fetch
+ *
+ * @var stdClass[]
+ */
+ private $incompleteEntities = array();
+
+ /**
* Batches operations on any elgg_get_*() or compatible function that supports
* an options array.
*
@@ -222,6 +229,17 @@ class ElggBatch
}
/**
+ * Tell the process that an entity was incomplete during a fetch
+ *
+ * @param stdClass $row
+ *
+ * @access private
+ */
+ public function reportIncompleteEntity(stdClass $row) {
+ $this->incompleteEntities[] = $row;
+ }
+
+ /**
* Fetches the next chunk of results
*
* @return bool
@@ -265,16 +283,16 @@ class ElggBatch
$current_options = array(
'limit' => $limit,
- 'offset' => $offset
+ 'offset' => $offset,
+ '__ElggBatch' => $this,
);
$options = array_merge($this->options, $current_options);
- $getter = $this->getter;
- if (is_string($getter)) {
- $this->results = $getter($options);
- } else {
- $this->results = call_user_func_array($getter, array($options));
+ $this->incompleteEntities = array();
+ $this->results = call_user_func_array($this->getter, array($options));
+ if ($this->incompleteEntities) {
+ // @todo what to do here?
}
if ($this->results) {
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 5cfeca6f8..b7f8c1466 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -891,6 +891,8 @@ function elgg_get_entities(array $options = array()) {
'joins' => array(),
'callback' => 'entity_row_to_elggstar',
+
+ '__ElggBatch' => null,
);
$options = array_merge($defaults, $options);
@@ -1008,7 +1010,7 @@ function elgg_get_entities(array $options = array()) {
}
if ($options['callback'] === 'entity_row_to_elggstar') {
- $dt = _elgg_fetch_entities_from_sql($query);
+ $dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
} else {
$dt = get_data($query, $options['callback']);
}
@@ -1043,13 +1045,14 @@ function elgg_get_entities(array $options = array()) {
/**
* Return entities from an SQL query generated by elgg_get_entities.
*
- * @param string $sql
+ * @param string $sql
+ * @param ElggBatch $batch
* @return ElggEntity[]
*
* @access private
* @throws LogicException
*/
-function _elgg_fetch_entities_from_sql($sql) {
+function _elgg_fetch_entities_from_sql($sql, ElggBatch $batch = null) {
static $plugin_subtype;
if (null === $plugin_subtype) {
$plugin_subtype = get_subtype_id('object', 'plugin');
@@ -1126,6 +1129,11 @@ function _elgg_fetch_entities_from_sql($sql) {
} catch (IncompleteEntityException $e) {
// don't let incomplete entities throw fatal errors
unset($rows[$i]);
+
+ // report incompletes to the batch process that spawned this query
+ if ($batch) {
+ $batch->reportIncompleteEntity($row);
+ }
}
}
}
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 62e4471e0..753d02915 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -578,6 +578,54 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
$this->assertEqual(11, $j);
}
+ public function testElggBatchHandlesBrokenEntities() {
+ $num_test_entities = 4;
+ $guids = array();
+ $now = time();
+ for ($i = $num_test_entities; $i > 0; $i--) {
+ $entity = new ElggObject();
+ $entity->type = 'object';
+ $entity->subtype = 'test_5357_subtype';
+ $entity->access_id = ACCESS_PUBLIC;
+ $entity->time_created = ($now - $i);
+ $entity->save();
+ $guids[] = $entity->guid;
+ _elgg_invalidate_cache_for_entity($entity->guid);
+ }
+
+ // break the second entity
+ $db_prefix = elgg_get_config('dbprefix');
+ delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid = {$guids[1]}");
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'test_5357_subtype',
+ 'order' => 'e.time_created ASC',
+ );
+
+ $entities_visited = array();
+
+ $batch = new ElggBatch('elgg_get_entities', $options, null, 2);
+ foreach ($batch as $entity) {
+ $entities_visited[$entity->guid] = true;
+ }
+
+ // All but the broken entity should have been visited
+ $this->assertEqual(count($entities_visited), $num_test_entities - 1);
+
+ // cleanup (including leftovers from previous tests)
+ $entity_rows = elgg_get_entities(array_merge($options, array(
+ 'callback' => '',
+ 'limit' => false,
+ )));
+ $guids = array();
+ foreach ($entity_rows as $row) {
+ $guids[] = $row->guid;
+ }
+ delete_data("DELETE FROM {$db_prefix}entities WHERE guid IN (" . implode(',', $guids) . ")");
+ delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
+ }
+
static function elgg_batch_callback_test($options, $reset = false) {
static $count = 1;