- Move 12 markdown files from root to docs/ subdirectories - Organize documentation by category: • docs/troubleshooting/ (1 file) - Technical troubleshooting guides • docs/deployment/ (4 files) - Deployment and security documentation • docs/guides/ (3 files) - Feature-specific guides • docs/planning/ (4 files) - Planning and improvement proposals Root directory cleanup: - Reduced from 16 to 4 markdown files in root - Only essential project files remain: • CLAUDE.md (AI instructions) • README.md (Main project readme) • CLEANUP_PLAN.md (Current cleanup plan) • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements) This improves: ✅ Documentation discoverability ✅ Logical organization by purpose ✅ Clean root directory ✅ Better maintainability
170 lines
5.1 KiB
PHP
170 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Queue\Services;
|
|
|
|
use App\Framework\Queue\ValueObjects\ProgressStep;
|
|
use App\Framework\Core\ValueObjects\Percentage;
|
|
|
|
/**
|
|
* Helper class for tracking progress through multiple steps
|
|
*/
|
|
final class StepProgressTracker
|
|
{
|
|
private int $currentStepIndex = 0;
|
|
private array $completedSteps = [];
|
|
|
|
public function __construct(
|
|
private readonly string $jobId,
|
|
private readonly array $steps,
|
|
private readonly ProgressManager $progressManager
|
|
) {
|
|
if (empty($steps)) {
|
|
throw new \InvalidArgumentException('Steps array cannot be empty');
|
|
}
|
|
|
|
// Validate step structure
|
|
foreach ($steps as $index => $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;
|
|
}
|
|
} |