Elgg  Version 2.3
ElggBatch.php
Go to the documentation of this file.
1 <?php
2 
4 
73 class ElggBatch implements BatchResult {
74 
80  private $results = array();
81 
87  private $getter = null;
88 
94  private $options = array();
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 = array();
179 
185  private $totalIncompletes = 0;
186 
209  public function __construct($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_get_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 = array();
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 
263  $this->incompleteEntities[] = $row;
264  }
265 
271  private function getNextResultsChunk() {
272 
273  // always reset results.
274  $this->results = array();
275 
276  if (!isset($this->validGetter)) {
277  $this->validGetter = is_callable($this->getter);
278  }
279 
280  if (!$this->validGetter) {
281  return false;
282  }
283 
284  $limit = $this->chunkSize;
285 
286  // if someone passed limit = 0 they want everything.
287  if ($this->limit != 0) {
288  if ($this->retrievedResults >= $this->limit) {
289  return false;
290  }
291 
292  // if original limit < chunk size, set limit to original limit
293  // else if the number of results we'll fetch if greater than the original limit
294  if ($this->limit < $this->chunkSize) {
295  $limit = $this->limit;
296  } elseif ($this->retrievedResults + $this->chunkSize > $this->limit) {
297  // set the limit to the number of results remaining in the original limit
298  $limit = $this->limit - $this->retrievedResults;
299  }
300  }
301 
302  if ($this->incrementOffset) {
303  $offset = $this->offset + $this->retrievedResults;
304  } else {
305  $offset = $this->offset + $this->totalIncompletes;
306  }
307 
308  $current_options = array(
309  'limit' => $limit,
310  'offset' => $offset,
311  '__ElggBatch' => $this,
312  );
313 
314  $options = array_merge($this->options, $current_options);
315 
316  $this->incompleteEntities = array();
317  $this->results = call_user_func($this->getter, $options);
318 
319  // batch result sets tend to be large; we don't want to cache these.
320  _elgg_services()->db->disableQueryCache();
321 
322  $num_results = count($this->results);
323  $num_incomplete = count($this->incompleteEntities);
324 
325  $this->totalIncompletes += $num_incomplete;
326 
327  if ($this->incompleteEntities) {
328  // pad the front of the results with nulls representing the incompletes
329  array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null));
330  // ...and skip past them
331  reset($this->results);
332  for ($i = 0; $i < $num_incomplete; $i++) {
333  next($this->results);
334  }
335  }
336 
337  if ($this->results) {
338  $this->chunkIndex++;
339 
340  // let the system know we've jumped past the nulls
341  $this->resultIndex = $num_incomplete;
342 
343  $this->retrievedResults += ($num_results + $num_incomplete);
344  if ($num_results == 0) {
345  // This fetch was *all* incompletes! We need to fetch until we can either
346  // offer at least one row to iterate over, or give up.
347  return $this->getNextResultsChunk();
348  }
349  _elgg_services()->db->enableQueryCache();
350  return true;
351  } else {
352  _elgg_services()->db->enableQueryCache();
353  return false;
354  }
355  }
356 
364  public function setIncrementOffset($increment = true) {
365  $this->incrementOffset = (bool) $increment;
366  }
367 
375  public function rewind() {
376  $this->resultIndex = 0;
377  $this->retrievedResults = 0;
378  $this->processedResults = 0;
379 
380  // only grab results if we haven't yet or we're crossing chunks
381  if ($this->chunkIndex == 0 || $this->limit > $this->chunkSize) {
382  $this->chunkIndex = 0;
383  $this->getNextResultsChunk();
384  }
385  }
386 
390  public function current() {
391  return current($this->results);
392  }
393 
397  public function key() {
398  return $this->processedResults;
399  }
400 
404  public function next() {
405  // if we'll be at the end.
406  if (($this->processedResults + 1) >= $this->limit && $this->limit > 0) {
407  $this->results = array();
408  return false;
409  }
410 
411  // if we'll need new results.
412  if (($this->resultIndex + 1) >= $this->chunkSize) {
413  if (!$this->getNextResultsChunk()) {
414  $this->results = array();
415  return false;
416  }
417 
418  $result = current($this->results);
419  } else {
420  // the function above resets the indexes, so only inc if not
421  // getting new set
422  $this->resultIndex++;
423  $result = next($this->results);
424  }
425 
426  $this->processedResults++;
427  return $result;
428  }
429 
433  public function valid() {
434  if (!is_array($this->results)) {
435  return false;
436  }
437  $key = key($this->results);
438  return ($key !== null && $key !== false);
439  }
440 
450  public function count() {
451  if (!is_callable($this->getter)) {
452  $inspector = new \Elgg\Debug\Inspector();
453  throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter));
454  }
455 
456  $options = array_merge($this->options, ['count' => true]);
457 
458  return call_user_func($this->getter, $options);
459  }
460 
468  public function __get($name) {
469  if ($name === 'options') {
470  elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
471  return $this->options;
472  }
473 
474  _elgg_services()->logger->warn("Read of non-existent property '$name'");
475  return null;
476  }
477 
486  public function __set($name, $value) {
487  if ($name === 'options') {
488  elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
489  }
490 
491  $this->{$name} = $value;
492  }
493 }
elgg_get_config($name, $site_guid=0)
Get an Elgg configuration value.
__construct($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
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
valid()
{}
Definition: ElggBatch.php:433
current()
{}
Definition: ElggBatch.php:390
$value
Definition: longtext.php:42
rewind()
Implements Iterator.
Definition: ElggBatch.php:375
$key
Definition: summary.php:34
reportIncompleteEntity(\stdClass $row)
Tell the process that an entity was incomplete during a fetch.
Definition: ElggBatch.php:262
elgg_deprecated_notice($msg, $dep_version, $backtrace_level=1)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:1098
_elgg_services(\Elgg\Di\ServiceProvider $services=null)
Get the global service provider.
Definition: autoloader.php:17
count()
Count the total results available at this moment.
Definition: ElggBatch.php:450
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:1375
next()
{}
Definition: ElggBatch.php:404
__get($name)
Read a property.
Definition: ElggBatch.php:468
__set($name, $value)
Write a property.
Definition: ElggBatch.php:486
key()
{}
Definition: ElggBatch.php:397
$row
Specifies a countable iterator, usually of result rows from a DB.
Definition: BatchResult.php:9
http free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:5
setIncrementOffset($increment=true)
Increment the offset from the original options array? Setting to false is required for callbacks that...
Definition: ElggBatch.php:364