- Introduced new SEO fields (meta_title, meta_description, primary_keyword, secondary_keywords, faq, internal_links, external_links, reading_time, canonical_url, og_image) to the Blog entity. - Added scheduling capability with a scheduled_at field to manage automatic publishing of blog posts. - Implemented representative ownership through a foreign key representation_id in the Blog entity, allowing representatives to manage their own posts. - Updated BlogController and RepresentationBlogController to handle new fields and ensure proper data handling for SEO and scheduling. - Created BlogWriter service to encapsulate the logic for applying SEO and scheduling fields to blog entities. - Added PublishScheduledBlogsMessage and its handler to manage the publishing of scheduled blogs. - Implemented ScheduledBlogPublisher service to publish drafts whose scheduled_at has arrived, respecting review status. - Created migration to update the database schema with new fields and constraints. - Added tests to ensure the correct functionality of new features, including SEO fields, representative scope, and scheduled publishing.
29 lines
842 B
PHP
29 lines
842 B
PHP
<?php
|
|
|
|
namespace App\Blog\Service;
|
|
|
|
use App\Blog\Entity\Blog;
|
|
use App\Blog\Repository\BlogRepository;
|
|
|
|
/**
|
|
* Publishes drafts whose scheduled_at has arrived. A post in the review workflow
|
|
* is published only once review_status = approved — the medical-review gate wins
|
|
* over the schedule, so AI-generated content is never auto-published unreviewed.
|
|
*/
|
|
class ScheduledBlogPublisher
|
|
{
|
|
public function __construct(private readonly BlogRepository $blogRepo) {}
|
|
|
|
/** @return int number of posts published */
|
|
public function publishDue(?int $now = null): int
|
|
{
|
|
$now = $now ?? time();
|
|
$due = $this->blogRepo->findDueForPublish($now);
|
|
foreach ($due as $blog) {
|
|
$blog->setStatus(Blog::STATUS_PUBLISHED);
|
|
$this->blogRepo->save($blog);
|
|
}
|
|
return count($due);
|
|
}
|
|
}
|