issueSummary = new ABJ_404_Solution_ImportIssueSummary(); } /** * A run that starts at the first data row with nothing counted yet. * * @return self */ public static function fresh(): self { return new self(); } /** * A run that continues an interrupted import from its persisted checkpoint. * * @param array $progress A checkpoint written by progressSnapshot(). * @return self */ public static function fromProgress(array $progress): self { $state = new self(); $state->resumeFrom = ABJ_404_Solution_ImportProgressStore::progressInt($progress, 'rows_processed', 0); $state->processed = ABJ_404_Solution_ImportProgressStore::progressInt($progress, 'processed_count', $state->resumeFrom); $state->valid = ABJ_404_Solution_ImportProgressStore::progressInt($progress, 'valid_count', 0); $state->invalid = ABJ_404_Solution_ImportProgressStore::progressInt($progress, 'invalid_count', 0); $state->overwritten = ABJ_404_Solution_ImportProgressStore::progressInt($progress, 'overwritten_count', 0); /** @var array $persistedIssues */ $persistedIssues = array(); if (isset($progress['issues']) && is_array($progress['issues'])) { $persistedIssues = $progress['issues']; } $persistedOmitted = max(0, ABJ_404_Solution_ImportProgressStore::progressInt( $progress, 'issues_omitted', 0 )); $state->issueSummary = new ABJ_404_Solution_ImportIssueSummary( $persistedIssues, $persistedOmitted ); return $state; } /** @return int Data rows to skip because an earlier upload already handled them. */ public function resumeFrom(): int { return $this->resumeFrom; } /** @return int */ public function processed(): int { return $this->processed; } /** @return int */ public function valid(): int { return $this->valid; } /** @return int */ public function invalid(): int { return $this->invalid; } /** @return int */ public function overwritten(): int { return $this->overwritten; } /** @return ABJ_404_Solution_ImportIssueSummary */ public function issueSummary(): ABJ_404_Solution_ImportIssueSummary { return $this->issueSummary; } /** @return string|null */ public function abortMessage(): ?string { return $this->abortMessage; } /** * Count one more row as handled, before its outcome is known. * * @return void */ public function beginRow(): void { $this->processed++; } /** * Record the diagnostics of the row that was just handled and classify it. * * A row with any diagnostic is invalid; otherwise it is valid, and it also * counts as an overwrite when it replaced an existing redirect. * * @param array $issues * @param bool $wasOverwrite * @return void */ public function recordRowOutcome(array $issues, bool $wasOverwrite): void { foreach ($issues as $issue) { $this->issueSummary->add($issue); } if (count($issues) > 0) { $this->invalid++; return; } $this->valid++; if ($wasOverwrite) { $this->overwritten++; } } /** * Stop the run and keep the message that is shown instead of a result. * * @param string $message * @return void */ public function abort(string $message): void { $this->abortMessage = $message; } /** * The checkpoint stored so a re-upload of the same file can resume. * * @param int $rowsProcessed Data rows to skip on resume. * @param int $processedCount Rows counted as processed at that point. * @return array */ public function progressSnapshot(int $rowsProcessed, int $processedCount): array { return array( 'rows_processed' => $rowsProcessed, 'processed_count' => $processedCount, 'valid_count' => $this->valid, 'invalid_count' => $this->invalid, 'overwritten_count' => $this->overwritten, 'issues' => $this->issueSummary->details(), 'issues_omitted' => $this->issueSummary->omittedCount(), ); } }