diff --git a/src/Progressable.php b/src/Progressable.php index 0997237..20fac73 100644 --- a/src/Progressable.php +++ b/src/Progressable.php @@ -17,6 +17,16 @@ trait Progressable { */ protected float $progress = 0; + /** + * The total steps for the progress. + */ + protected ?int $totalSteps = null; + + /** + * The current step of the progress. + */ + protected ?int $currentStep = null; + /** * The callback function for saving cache data. * @@ -268,6 +278,10 @@ public function setLocalProgress(float $progress): static { $oldProgress = $this->progress; $this->progress = max(0, min(100, $progress)); + if ($this->totalSteps !== null && $this->totalSteps > 0) { + $this->currentStep = (int) round(($this->progress / 100) * $this->totalSteps); + } + $this->updateLocalProgressData($this->progress); // Fire progress change callback @@ -297,6 +311,14 @@ protected function updateLocalProgressData(float $progress): static { $localData['message'] = $this->statusMessage; } + if ($this->totalSteps !== null) { + $localData['total_steps'] = $this->totalSteps; + } + + if ($this->currentStep !== null) { + $localData['current_step'] = $this->currentStep; + } + if (! empty($this->metadata)) { $localData['metadata'] = $this->metadata; } @@ -518,4 +540,60 @@ public function onComplete(callable $callback): static { return $this; } + + /** + * Set the total number of steps. + * + * @param int $totalSteps The total number of steps. + * @return $this + */ + public function setTotalSteps(int $totalSteps): static { + $this->totalSteps = $totalSteps; + + return $this; + } + + /** + * Get the total number of steps. + */ + public function getTotalSteps(): ?int { + return $this->totalSteps; + } + + /** + * Set the current step. + * + * @param int $step The current step. + * @return $this + */ + public function setStep(int $step): static { + $this->currentStep = $step; + + if ($this->totalSteps !== null && $this->totalSteps > 0) { + $progress = ($this->currentStep / $this->totalSteps) * 100; + + return $this->setLocalProgress($progress); + } + + return $this->updateLocalProgressData($this->progress); + } + + /** + * Get the current step. + */ + public function getStep(): ?int { + return $this->currentStep; + } + + /** + * Increment the current step. + * + * @param int $amount The amount to increment. + * @return $this + */ + public function incrementStep(int $amount = 1): static { + $current = $this->currentStep ?? 0; + + return $this->setStep($current + $amount); + } } diff --git a/tests/ProgressableTest.php b/tests/ProgressableTest.php index 40f5003..2187c6b 100644 --- a/tests/ProgressableTest.php +++ b/tests/ProgressableTest.php @@ -485,4 +485,72 @@ public function test_merge_metadata(): void { $this->assertEquals('new_value1', $storedMetadata['key1']); $this->assertEquals('value2', $storedMetadata['key2']); } + + public function test_set_total_steps(): void { + $this->setOverallUniqueName('test_total_steps_'.$this->testId); + $this->setTotalSteps(10); + + $this->assertEquals(10, $this->getTotalSteps()); + } + + public function test_step_based_progress(): void { + $this->setOverallUniqueName('test_step_progress_'.$this->testId); + $this->setTotalSteps(10); + + $this->setStep(5); + $this->assertEquals(5, $this->getStep()); + $this->assertEquals(50, $this->getLocalProgress()); + + $this->setStep(2); + $this->assertEquals(2, $this->getStep()); + $this->assertEquals(20, $this->getLocalProgress()); + } + + public function test_increment_step(): void { + $this->setOverallUniqueName('test_increment_step_'.$this->testId); + $this->setTotalSteps(10); + $this->setStep(1); + + $this->incrementStep(); + $this->assertEquals(2, $this->getStep()); + $this->assertEquals(20, $this->getLocalProgress()); + + $this->incrementStep(3); + $this->assertEquals(5, $this->getStep()); + $this->assertEquals(50, $this->getLocalProgress()); + } + + public function test_sync_between_progress_and_steps(): void { + $this->setOverallUniqueName('test_sync_steps_'.$this->testId); + $this->setTotalSteps(100); + + $this->setLocalProgress(50); + $this->assertEquals(50, $this->getStep()); + + $this->setLocalProgress(25.5); + $this->assertEquals(26, $this->getStep()); // round(25.5) = 26 + } + + public function test_step_data_in_storage(): void { + $this->setOverallUniqueName('test_storage_steps_'.$this->testId); + $this->setTotalSteps(10); + $this->setStep(5); + + $progressData = $this->getOverallProgressData(); + $localData = $progressData[$this->getLocalKey()]; + + $this->assertArrayHasKey('total_steps', $localData); + $this->assertEquals(10, $localData['total_steps']); + + $this->assertArrayHasKey('current_step', $localData); + $this->assertEquals(5, $localData['current_step']); + } + + public function test_set_step_without_total_steps(): void { + $this->setOverallUniqueName('test_step_without_total_'.$this->testId); + $this->setStep(5); + + $this->assertEquals(5, $this->getStep()); + $this->assertEquals(0, $this->getLocalProgress()); + } }