Elgg  Version 3.0
ElggBatch.php
Go to the documentation of this file.
1 <?php
2 
4 
73 class ElggBatch implements BatchResult {
74 
80  private $results = [];
81 
87  private $getter = null;
88 
94  private $options = [];
95 
101  private $chunkSize = 25;
102 
108  private $callback = null;
109 
115  private $offset = 0;
116 
122  private $limit = 0;
123 
129  private $retrievedResults = 0;
130 
136  private $resultIndex = 0;
137 
143  private $chunkIndex = 0;
144 
150  private $processedResults = 0;
151 
157  private $validGetter = null;
158 
164  public $callbackResult = null;
165 
171  private $incrementOffset = true;
172 
178  private $incompleteEntities = [];
179 
185  private $totalIncompletes = 0;
186 
209  public function __construct(callable $getter, $options, $callback = null, $chunk_size = 25,
210  $inc_offset = true) {
211 
212  $this->getter = $getter;
213  $this->options = $options;
214  $this->callback = $callback;
215  $this->chunkSize = $chunk_size;
216  $this->setIncrementOffset($inc_offset);
217 
218  if ($this->chunkSize <= 0) {
219  $this->chunkSize = 25;
220  }
221 
222  // store these so we can compare later
223  $this->offset = elgg_extract('offset', $options, 0);
224  $this->limit = elgg_extract('limit', $options, _elgg_config()->default_limit);
225 
226  // if passed a callback, create a new \ElggBatch with the same options
227  // and pass each to the callback.
228  if ($callback && is_callable($callback)) {
229  $batch = new \ElggBatch($getter, $options, null, $chunk_size, $inc_offset);
230 
231  $all_results = null;
232 
233  foreach ($batch as $result) {
234  $result = call_user_func($callback, $result, $getter, $options);
235 
236  if (!isset($all_results)) {
237  if ($result === true || $result === false || $result === null) {
238  $all_results = $result;
239  } else {
240  $all_results = [];
241  }
242  }
243 
244  if (($result === true || $result === false || $result === null) && !is_array($all_results)) {
245  $all_results = $result && $all_results;
246  } else {
247  $all_results[] = $result;
248  }
249  }
250 
251  $this->callbackResult = $all_results;
252  }
253  }
254 
260  private function getNextResultsChunk() {
261 
262  // always reset results.
263  $this->results = [];
264 
265  if (!isset($this->validGetter)) {
266  $this->validGetter = is_callable($this->getter);
267  }
268 
269  if (!$this->validGetter) {
270  return false;
271  }
272 
273  $limit = $this->chunkSize;
274 
275  // if someone passed limit = 0 they want everything.
276  if ($this->limit != 0) {
277  if ($this->retrievedResults >= $this->limit) {
278  return false;
279  }
280 
281  // if original limit < chunk size, set limit to original limit
282  // else if the number of results we'll fetch if greater than the original limit
283  if ($this->limit < $this->chunkSize) {
284  $limit = $this->limit;
285  } elseif ($this->retrievedResults + $this->chunkSize > $this->limit) {
286  // set the limit to the number of results remaining in the original limit
287  $limit = $this->limit - $this->retrievedResults;
288  }
289  }
290 
291  if ($this->incrementOffset) {
292  $offset = $this->offset + $this->retrievedResults;
293  } else {
294  $offset = $this->offset + $this->totalIncompletes;
295  }
296 
297  $current_options = [
298  'limit' => $limit,
299  'offset' => $offset,
300  '__ElggBatch' => $this,
301  ];
302 
303  $options = array_merge($this->options, $current_options);
304 
305  $this->incompleteEntities = [];
306  $this->results = call_user_func($this->getter, $options);
307 
308  // batch result sets tend to be large; we don't want to cache these.
309  _elgg_services()->queryCache->disable();
310 
311  $num_results = count($this->results);
312  $num_incomplete = count($this->incompleteEntities);
313 
314  $this->totalIncompletes += $num_incomplete;
315 
316  if (!empty($this->incompleteEntities)) {
317  // pad the front of the results with nulls representing the incompletes
318  array_splice($this->results, 0, 0, array_pad([], $num_incomplete, null));
319  // ...and skip past them
320  reset($this->results);
321  for ($i = 0; $i < $num_incomplete; $i++) {
322  next($this->results);
323  }
324  }
325 
326  if ($this->results) {
327  $this->chunkIndex++;
328 
329  // let the system know we've jumped past the nulls
330  $this->resultIndex = $num_incomplete;
331 
332  $this->retrievedResults += ($num_results + $num_incomplete);
333  if ($num_results == 0) {
334  // This fetch was *all* incompletes! We need to fetch until we can either
335  // offer at least one row to iterate over, or give up.
336  return $this->getNextResultsChunk();
337  }
338  _elgg_services()->queryCache->enable();
339  return true;
340  } else {
341  _elgg_services()->queryCache->enable();
342  return false;
343  }
344  }
345 
353  public function setIncrementOffset($increment = true) {
354  $this->incrementOffset = (bool) $increment;
355  }
356 
362  public function setChunkSize($size = 25) {
363  $this->chunkSize = $size;
364  }
372  public function rewind() {
373  $this->resultIndex = 0;
374  $this->retrievedResults = 0;
375  $this->processedResults = 0;
376 
377  // only grab results if we haven't yet or we're crossing chunks
378  if ($this->chunkIndex == 0 || $this->limit > $this->chunkSize) {
379  $this->chunkIndex = 0;
380  $this->getNextResultsChunk();
381  }
382  }
383 
387  public function current() {
388  return current($this->results);
389  }
390 
394  public function key() {
395  return $this->processedResults;
396  }
397 
401  public function next() {
402  // if we'll be at the end.
403  if (($this->processedResults + 1) >= $this->limit && $this->limit > 0) {
404  $this->results = [];
405  return false;
406  }
407 
408  // if we'll need new results.
409  if (($this->resultIndex + 1) >= $this->chunkSize) {
410  if (!$this->getNextResultsChunk()) {
411  $this->results = [];
412  return false;
413  }
414 
415  $result = current($this->results);
416  } else {
417  // the function above resets the indexes, so only inc if not
418  // getting new set
419  $this->resultIndex++;
420  $result = next($this->results);
421  }
422 
423  $this->processedResults++;
424  return $result;
425  }
426 
430  public function valid() {
431  if (!is_array($this->results)) {
432  return false;
433  }
434  $key = key($this->results);
435  return ($key !== null && $key !== false);
436  }
437 
447  public function count() {
448  if (!is_callable($this->getter)) {
449  $inspector = new \Elgg\Debug\Inspector();
450  throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter));
451  }
452 
453  $options = array_merge($this->options, ['count' => true]);
454 
455  return call_user_func($this->getter, $options);
456  }
457 }
__construct(callable $getter, $options, $callback=null, $chunk_size=25, $inc_offset=true)
Batches operations on any elgg_get_*() or compatible function that supports an options array...
Definition: ElggBatch.php:209
$CONFIG default_limit
The default "limit" used in site queries.
Definition: config.php:121
valid()
{}
Definition: ElggBatch.php:430
current()
{}
Definition: ElggBatch.php:387
$size
Definition: remove.php:24
rewind()
Implements Iterator.
Definition: ElggBatch.php:372
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif(is_callable([$item, 'getType']))
Definition: item.php:39
count()
Count the total results available at this moment.
Definition: ElggBatch.php:447
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:1131
next()
{}
Definition: ElggBatch.php:401
if($container instanceof ElggGroup &&$container->guid!=elgg_get_page_owner_guid()) $key
Definition: summary.php:55
setChunkSize($size=25)
Set chunk size.
Definition: ElggBatch.php:362
_elgg_config()
Get the Elgg config service.
key()
{}
Definition: ElggBatch.php:394
_elgg_services()
Get the global service provider.
Definition: elgglib.php:1292
Specifies a countable iterator, usually of result rows from a DB.
Definition: BatchResult.php:9
setIncrementOffset($increment=true)
Increment the offset from the original options array? Setting to false is required for callbacks that...
Definition: ElggBatch.php:353