diff options
| -rw-r--r-- | engine/classes/ElggBatch.php | 30 | ||||
| -rw-r--r-- | engine/lib/entities.php | 14 | ||||
| -rw-r--r-- | engine/tests/api/helpers.php | 48 | 
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;  | 
