Elgg  Version 3.0
Loop.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Upgrade;
4 
6 use Elgg\Loggable;
7 use Elgg\Logger;
8 use ElggUpgrade;
11 
16 class Loop {
17 
18  use Loggable;
19 
23  protected $upgrade;
24 
28  protected $result;
29 
33  protected $batch;
34 
38  protected $max_duration;
39 
43  protected $count;
44 
48  protected $processed;
49 
53  protected $offset;
54 
58  protected $progress;
59 
68  public function __construct(
72  Logger $logger
73  ) {
74  $this->upgrade = $upgrade;
75 
76  // Get the class taking care of the actual upgrading
77  $this->batch = $upgrade->getBatch();
78  if (!$this->batch) {
79  throw new \RuntimeException(elgg_echo('admin:upgrades:error:invalid_batch', [
80  $upgrade->getDisplayName(),
81  $upgrade->guid
82  ]));
83  }
84 
85  $this->result = $result;
86  $this->progress = $progress;
87  $this->logger = $logger;
88 
89  $this->count = $this->batch->countItems();
90  $this->processed = (int) $upgrade->processed;
91  $this->offset = (int) $upgrade->offset;
92  }
93 
101  public function loop($max_duration = null) {
102 
103  $started = microtime(true);
104 
105  $progress = $this->progress->start($this->upgrade->getDisplayName(), $this->count);
106 
107  while ($this->canContinue($started, $max_duration)) {
108  $this->runBatch($progress);
109  }
110 
111  $this->progress->finish($progress);
112 
113  $this->upgrade->processed = $this->processed;
114  $this->upgrade->offset = $this->offset;
115 
116  if (!$this->isCompleted()) {
117  return;
118  }
119 
120  // Upgrade is finished
121  if ($this->result->getFailureCount()) {
122  // The upgrade was finished with errors. Reset offset
123  // and errors so the upgrade can start from a scratch
124  // if attempted to run again.
125  $this->upgrade->processed = 0;
126  $this->upgrade->offset = 0;
127  } else {
128  // Everything has been processed without errors
129  // so the upgrade can be marked as completed.
130  $this->upgrade->setCompleted();
131  $this->result->markComplete();
132  }
133 
134  $this->report();
135  }
136 
144  protected function runBatch(ProgressBar $progress) {
145  try {
146  $this->batch->run($this->result, $this->offset);
147  } catch (\Exception $e) {
148  $this->logger->error($e);
149 
150  $this->result->addError($e->getMessage());
151  $this->result->addFailures(1);
152  }
153 
154  $failure_count = $this->result->getFailureCount();
155  $success_count = $this->result->getSuccessCount();
156 
157  $total = $this->upgrade->processed + $failure_count + $success_count;
158 
159  $progress->advance($total - $this->processed);
160 
161  if ($this->batch->needsIncrementOffset()) {
162  // Offset needs to incremented by the total amount of processed
163  // items so the upgrade we won't get stuck upgrading the same
164  // items over and over.
165  $this->offset = $total;
166  } else {
167  // Offset doesn't need to be incremented, so we mark only
168  // the items that caused a failure.
169  $this->offset = $this->upgrade->offset + $failure_count;
170  }
171 
172  $this->processed = $total;
173  }
174 
179  protected function report() {
180  $upgrade_name = $this->upgrade->getDisplayName();
181 
182  if ($this->upgrade->isCompleted()) {
183  $ts = $this->upgrade->getCompletedTime();
184  $dt = new \DateTime();
185  $dt->setTimestamp((int) $ts);
186  $format = elgg_get_config('date_format') ? : DATE_ISO8601;
187 
188  if ($this->result->getFailureCount()) {
189  $msg = elgg_echo('admin:upgrades:completed:errors', [
190  $upgrade_name,
191  $dt->format($format),
192  $this->result->getFailureCount(),
193  ]);
194 
195  register_error($msg);
196  } else {
197  $msg = elgg_echo('admin:upgrades:completed', [
198  $upgrade_name,
199  $dt->format($format),
200  ]);
201 
202  system_message($msg);
203  }
204  } else {
205  $msg = elgg_echo('admin:upgrades:failed', [
206  $upgrade_name
207  ]);
208 
209  register_error($msg);
210  }
211 
212  foreach ($this->result->getErrors() as $error) {
213  $this->logger->log(LogLevel::ERROR, $error);
214  }
215  }
216 
225  protected function canContinue($started, $max_duration = null) {
226  if (!isset($max_duration)) {
227  $max_duration = elgg_get_config('batch_run_time_in_secs');
228  }
229 
230  if ($max_duration && (microtime(true) - $started) >= $max_duration) {
231  return false;
232  }
233 
234  return !$this->isCompleted();
235  }
236 
241  protected function isCompleted() {
242  if ($this->batch->shouldBeSkipped()) {
243  return true;
244  }
245 
246  if ($this->result && $this->result->wasMarkedComplete()) {
247  return true;
248  }
249 
250  return $this->count !== Batch::UNKNOWN_COUNT && $this->processed >= $this->count;
251  }
252 }
$format
Definition: date.php:36
const UNKNOWN_COUNT
countItems() should return this if it doesn&#39;t know how many items remain.
Definition: Batch.php:15
canContinue($started, $max_duration=null)
Check if the loop cand and should continue.
Definition: Loop.php:225
runBatch(ProgressBar $progress)
Run batch.
Definition: Loop.php:144
trait Loggable
Enables adding a logger.
Definition: Loggable.php:12
isCompleted()
Check if upgrade has completed.
Definition: Loop.php:241
elgg_echo($message_key, array $args=[], $language="")
Given a message key, returns an appropriately translated full-text string.
Definition: languages.php:21
__construct(ElggUpgrade $upgrade, Result $result, Progress $progress, Logger $logger)
Constructor.
Definition: Loop.php:68
$error
Bad request error.
Definition: 400.php:6
Logger.
Definition: Logger.php:25
$dt
Definition: time.php:69
getBatch()
Return instance of the class that processes the data.
CLI Progress reporter.
Definition: Progress.php:11
Result of a single BatchUpgrade run.
Definition: Result.php:8
elgg system_message
Wrapper function for system_messages.
Definition: elgglib.js:382
getDisplayName()
{}
elgg register_error
Wrapper function for system_messages.
Definition: elgglib.js:391
report()
Report loop results.
Definition: Loop.php:179
elgg ajax ERROR
Definition: ajax.js:33
loop($max_duration=null)
Run upgrade loop for a preset number of seconds.
Definition: Loop.php:101
elgg_get_config($name, $default=null)
Get an Elgg configuration value.
Upgrade loop Executes upgrade batches for a given duration of time.
Definition: Loop.php:16