article; $routeArticle->update(['publish_status' => PublishStatusEnum::PUBLISHING]); try { $extractedData = $this->resolvePublishData($article); $outcome = $this->hasPublishableContent($extractedData) ? $this->publishingService->publishRouteArticle($routeArticle, $extractedData) : PublishOutcome::failure('Could not recover the article content to publish'); } catch (Exception $e) { $routeArticle->recordPublishFailed($e->getMessage()); ActionPerformed::dispatch('Failed to publish article', LogLevelEnum::ERROR, [ 'article_id' => $article->id, 'error' => $e->getMessage(), ]); ActivityLogged::dispatch( ActivityTypeEnum::ERROR, "Failed to publish \"{$article->title}\"", ['error' => $e->getMessage()], $article, ); $this->notificationService->send( NotificationTypeEnum::PUBLISH_FAILED, NotificationSeverityEnum::ERROR, "Publish failed: {$article->title}", $e->getMessage(), $article, ); throw $e; } match (true) { $outcome->succeeded() => $this->recordPublished($routeArticle), $outcome->wasSkipped() => $this->recordSkipped($routeArticle, $outcome), default => $this->recordFailed($routeArticle, $outcome), }; return $outcome; } /** * @param array $extractedData */ private function hasPublishableContent(array $extractedData): bool { return ! empty($extractedData['description']); } /** * @return array */ private function resolvePublishData(Article $article): array { if (empty($article->description) && empty($article->image_url)) { return $this->fetchArticleData->execute($article); } return [ 'title' => $article->title, 'description' => $article->description, 'thumbnail' => $article->image_url, ]; } private function recordPublished(RouteArticle $routeArticle): void { $routeArticle->update([ 'publish_status' => PublishStatusEnum::PUBLISHED, 'publish_error' => null, ]); ActionPerformed::dispatch('Published article', LogLevelEnum::INFO, [ 'article_id' => $routeArticle->article->id, 'title' => $routeArticle->article->title, ]); ActivityLogged::dispatch( ActivityTypeEnum::PUBLISH, "Published \"{$routeArticle->article->title}\"", ['route_article_id' => $routeArticle->id], $routeArticle->article, ); } private function recordSkipped(RouteArticle $routeArticle, PublishOutcome $outcome): void { $routeArticle->update(['publish_status' => PublishStatusEnum::SKIPPED]); ActionPerformed::dispatch('Skipped publishing article', LogLevelEnum::INFO, [ 'article_id' => $routeArticle->article->id, 'title' => $routeArticle->article->title, 'reason' => $outcome->reason, ]); ActivityLogged::dispatch( ActivityTypeEnum::PUBLISH, "Skipped \"{$routeArticle->article->title}\"", ['skipped' => true, 'reason' => $outcome->reason], $routeArticle->article, ); } private function recordFailed(RouteArticle $routeArticle, PublishOutcome $outcome): void { $article = $routeArticle->article; $routeArticle->recordPublishFailed($outcome->reason ?? 'Publishing failed'); ActionPerformed::dispatch('No publication created for article', LogLevelEnum::WARNING, [ 'article_id' => $article->id, 'title' => $article->title, 'reason' => $outcome->reason, ]); ActivityLogged::dispatch( ActivityTypeEnum::ERROR, "Failed to publish \"{$article->title}\"", ['reason' => $outcome->reason], $article, ); $this->notificationService->send( NotificationTypeEnum::PUBLISH_FAILED, NotificationSeverityEnum::WARNING, "Publish failed: {$article->title}", $outcome->reason ?? 'No publication was created for this article.', $article, ); } }