$step) { if (!is_array($step) || !isset($step['name'], $step['description'])) { throw new \InvalidArgumentException("Step at index {$index} must have 'name' and 'description' keys"); } } } public function start(string $message = 'Starting multi-step job'): void { $this->progressManager->startJob($this->jobId, $message); } public function completeCurrentStep(?array $metadata = null): void { if ($this->currentStepIndex >= count($this->steps)) { throw new \RuntimeException('All steps have already been completed'); } $step = $this->steps[$this->currentStepIndex]; $this->progressManager->completeJobStep( $this->jobId, $step['name'], $step['description'], $metadata ); $this->completedSteps[] = $step['name']; $this->currentStepIndex++; // Update overall progress percentage $percentage = ($this->currentStepIndex / count($this->steps)) * 100; $message = sprintf( 'Completed step %d of %d: %s', $this->currentStepIndex, count($this->steps), $step['description'] ); $this->progressManager->updateJobProgress( $this->jobId, $percentage, $message, [ 'current_step' => $this->currentStepIndex, 'total_steps' => count($this->steps), 'completed_steps' => $this->completedSteps ] ); } public function updateCurrentStepProgress( float $stepPercentage, string $message, ?array $metadata = null ): void { if ($this->currentStepIndex >= count($this->steps)) { throw new \RuntimeException('All steps have already been completed'); } // Calculate overall percentage: completed steps + current step progress $completedStepsPercentage = ($this->currentStepIndex / count($this->steps)) * 100; $currentStepContribution = ($stepPercentage / 100) * (100 / count($this->steps)); $totalPercentage = $completedStepsPercentage + $currentStepContribution; $step = $this->steps[$this->currentStepIndex]; $fullMessage = sprintf( 'Step %d of %d (%s): %s', $this->currentStepIndex + 1, count($this->steps), $step['name'], $message ); $fullMetadata = array_merge($metadata ?? [], [ 'current_step' => $this->currentStepIndex + 1, 'total_steps' => count($this->steps), 'step_name' => $step['name'], 'step_percentage' => $stepPercentage, 'completed_steps' => $this->completedSteps ]); $this->progressManager->updateJobProgress( $this->jobId, $totalPercentage, $fullMessage, $fullMetadata ); } public function complete(string $message = 'All steps completed successfully'): void { // Complete any remaining steps if not all were explicitly completed while ($this->currentStepIndex < count($this->steps)) { $this->completeCurrentStep(); } $this->progressManager->completeJob($this->jobId, $message); } public function fail(string $message, ?\Throwable $exception = null): void { $step = $this->getCurrentStep(); $fullMessage = sprintf( 'Failed on step %d of %d (%s): %s', $this->currentStepIndex + 1, count($this->steps), $step['name'] ?? 'unknown', $message ); $this->progressManager->failJob($this->jobId, $fullMessage, $exception); } public function getCurrentStep(): ?array { if ($this->currentStepIndex >= count($this->steps)) { return null; } return $this->steps[$this->currentStepIndex]; } public function getRemainingSteps(): array { return array_slice($this->steps, $this->currentStepIndex); } public function getCompletedSteps(): array { return $this->completedSteps; } public function isComplete(): bool { return $this->currentStepIndex >= count($this->steps); } public function getProgress(): float { return ($this->currentStepIndex / count($this->steps)) * 100; } }