You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
6.1 KiB
208 lines
6.1 KiB
<?php |
|
|
|
declare(strict_types=1); |
|
|
|
namespace App\Service; |
|
|
|
use App\Dto\CategoryDraft; |
|
use Psr\Log\LoggerInterface; |
|
use Symfony\Component\Workflow\WorkflowInterface; |
|
|
|
/** |
|
* Service for managing reading list workflow transitions |
|
*/ |
|
class ReadingListWorkflowService |
|
{ |
|
public function __construct( |
|
private readonly WorkflowInterface $readingListWorkflow, |
|
private readonly LoggerInterface $logger, |
|
) {} |
|
|
|
/** |
|
* Initialize a new reading list draft |
|
*/ |
|
public function initializeDraft(CategoryDraft $draft): void |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'start_draft')) { |
|
$this->readingListWorkflow->apply($draft, 'start_draft'); |
|
$this->logger->info('Reading list workflow: started draft', [ |
|
'slug' => $draft->slug |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Update metadata (title/summary) and transition if needed |
|
*/ |
|
public function updateMetadata(CategoryDraft $draft): void |
|
{ |
|
if ($draft->title !== '' && $this->readingListWorkflow->can($draft, 'add_metadata')) { |
|
$this->readingListWorkflow->apply($draft, 'add_metadata'); |
|
$this->logger->info('Reading list workflow: metadata added', [ |
|
'slug' => $draft->slug, |
|
'title' => $draft->title |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Add articles and transition if needed |
|
*/ |
|
public function addArticles(CategoryDraft $draft): void |
|
{ |
|
if (!empty($draft->articles) && $this->readingListWorkflow->can($draft, 'add_articles')) { |
|
$this->readingListWorkflow->apply($draft, 'add_articles'); |
|
$this->logger->info('Reading list workflow: articles added', [ |
|
'slug' => $draft->slug, |
|
'count' => count($draft->articles) |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Mark as ready for review |
|
*/ |
|
public function markReadyForReview(CategoryDraft $draft): bool |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'ready_for_review')) { |
|
$this->readingListWorkflow->apply($draft, 'ready_for_review'); |
|
$this->logger->info('Reading list workflow: ready for review', [ |
|
'slug' => $draft->slug |
|
]); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
/** |
|
* Start the publishing process |
|
*/ |
|
public function startPublishing(CategoryDraft $draft): void |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'start_publishing')) { |
|
$this->readingListWorkflow->apply($draft, 'start_publishing'); |
|
$this->logger->info('Reading list workflow: publishing started', [ |
|
'slug' => $draft->slug |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Complete the publishing process |
|
*/ |
|
public function completePublishing(CategoryDraft $draft): void |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'complete_publishing')) { |
|
$this->readingListWorkflow->apply($draft, 'complete_publishing'); |
|
$this->logger->info('Reading list workflow: published', [ |
|
'slug' => $draft->slug |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Edit a published reading list |
|
*/ |
|
public function editPublished(CategoryDraft $draft): void |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'edit_published')) { |
|
$this->readingListWorkflow->apply($draft, 'edit_published'); |
|
$this->logger->info('Reading list workflow: editing published list', [ |
|
'slug' => $draft->slug |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Cancel the draft |
|
*/ |
|
public function cancel(CategoryDraft $draft): void |
|
{ |
|
if ($this->readingListWorkflow->can($draft, 'cancel')) { |
|
$this->readingListWorkflow->apply($draft, 'cancel'); |
|
$this->logger->info('Reading list workflow: cancelled', [ |
|
'slug' => $draft->slug |
|
]); |
|
} |
|
} |
|
|
|
/** |
|
* Get current state of the reading list |
|
*/ |
|
public function getCurrentState(CategoryDraft $draft): string |
|
{ |
|
return $draft->getWorkflowState(); |
|
} |
|
|
|
/** |
|
* Get available transitions |
|
* @return array<string> |
|
*/ |
|
public function getAvailableTransitions(CategoryDraft $draft): array |
|
{ |
|
return $this->readingListWorkflow->getEnabledTransitions($draft); |
|
} |
|
|
|
/** |
|
* Check if draft is ready to publish |
|
*/ |
|
public function isReadyToPublish(CategoryDraft $draft): bool |
|
{ |
|
return $this->readingListWorkflow->can($draft, 'start_publishing'); |
|
} |
|
|
|
/** |
|
* Get a human-readable status message |
|
*/ |
|
public function getStatusMessage(CategoryDraft $draft): string |
|
{ |
|
return match ($draft->getWorkflowState()) { |
|
'empty' => 'Not started', |
|
'draft' => 'Draft created', |
|
'has_metadata' => 'Title and summary added', |
|
'has_articles' => 'Articles added', |
|
'ready_for_review' => 'Ready to publish', |
|
'publishing' => 'Publishing...', |
|
'published' => 'Published', |
|
'editing' => 'Editing published list', |
|
default => 'Unknown state', |
|
}; |
|
} |
|
|
|
/** |
|
* Get a badge color for the current state |
|
*/ |
|
public function getStateBadgeColor(CategoryDraft $draft): string |
|
{ |
|
return match ($draft->getWorkflowState()) { |
|
'empty' => 'secondary', |
|
'draft' => 'info', |
|
'has_metadata' => 'info', |
|
'has_articles' => 'primary', |
|
'ready_for_review' => 'success', |
|
'publishing' => 'warning', |
|
'published' => 'success', |
|
'editing' => 'warning', |
|
default => 'secondary', |
|
}; |
|
} |
|
|
|
/** |
|
* Get completion percentage (for progress bar) |
|
*/ |
|
public function getCompletionPercentage(CategoryDraft $draft): int |
|
{ |
|
return match ($draft->getWorkflowState()) { |
|
'empty' => 0, |
|
'draft' => 20, |
|
'has_metadata' => 40, |
|
'has_articles' => 60, |
|
'ready_for_review' => 80, |
|
'publishing' => 90, |
|
'published' => 100, |
|
'editing' => 50, |
|
default => 0, |
|
}; |
|
} |
|
} |
|
|
|
|