feat(blog): add SEO fields, scheduling, and representative ownership to blog posts

- 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.
This commit is contained in:
hamed
2026-07-23 22:05:23 +03:30
parent 14730e43ce
commit 62b2f28c4f
14 changed files with 786 additions and 0 deletions
+4
View File
@@ -3,6 +3,7 @@
namespace App;
use App\Appointment\Message\ExpireAppointmentsMessage;
use App\Blog\Message\PublishScheduledBlogsMessage;
use App\Shared\Logging\Message\PruneLogsMessage;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\RecurringMessage;
@@ -28,6 +29,9 @@ class Schedule implements ScheduleProviderInterface
)
->add(
RecurringMessage::every('1 day', new PruneLogsMessage())
)
->add(
RecurringMessage::every('1 minute', new PublishScheduledBlogsMessage())
);
}
}