Files
clinicpro/migrations/Version20260723174500.php
T
hamed 62b2f28c4f 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.
2026-07-23 22:05:23 +03:30

46 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260723174500 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add SEO fields, scheduling (scheduled_at) and representative ownership (representation_id) to blogs';
}
public function up(Schema $schema): void
{
// Scoped to the blogs table only. Unrelated project-wide schema drift that
// doctrine:diff also emitted is deliberately left out of this feature migration.
// Nullable columns + representation FK column.
$this->addSql('ALTER TABLE blogs ADD meta_title VARCHAR(255) DEFAULT NULL, ADD meta_description VARCHAR(500) DEFAULT NULL, ADD primary_keyword VARCHAR(255) DEFAULT NULL, ADD reading_time INT DEFAULT NULL, ADD canonical_url VARCHAR(500) DEFAULT NULL, ADD og_image VARCHAR(500) DEFAULT NULL, ADD scheduled_at INT DEFAULT NULL, ADD representation_id INT DEFAULT NULL');
// JSON NOT NULL columns can't be added directly to a table with rows (the
// empty backfill fails json_valid). Add nullable, backfill '[]', then enforce.
$this->addSql('ALTER TABLE blogs ADD secondary_keywords JSON DEFAULT NULL, ADD faq JSON DEFAULT NULL, ADD internal_links JSON DEFAULT NULL, ADD external_links JSON DEFAULT NULL');
$this->addSql("UPDATE blogs SET secondary_keywords = '[]', faq = '[]', internal_links = '[]', external_links = '[]'");
$this->addSql('ALTER TABLE blogs MODIFY secondary_keywords JSON NOT NULL, MODIFY faq JSON NOT NULL, MODIFY internal_links JSON NOT NULL, MODIFY external_links JSON NOT NULL');
$this->addSql('ALTER TABLE blogs ADD CONSTRAINT FK_F41BCA7046CE82F4 FOREIGN KEY (representation_id) REFERENCES representations (id) ON DELETE SET NULL');
$this->addSql('CREATE INDEX IDX_F41BCA7046CE82F4 ON blogs (representation_id)');
$this->addSql('CREATE INDEX idx_blogs_scheduled_at ON blogs (scheduled_at)');
$this->addSql('CREATE INDEX idx_blogs_representation ON blogs (representation_id, created_at)');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE blogs DROP FOREIGN KEY FK_F41BCA7046CE82F4');
$this->addSql('DROP INDEX IDX_F41BCA7046CE82F4 ON blogs');
$this->addSql('DROP INDEX idx_blogs_scheduled_at ON blogs');
$this->addSql('DROP INDEX idx_blogs_representation ON blogs');
$this->addSql('ALTER TABLE blogs DROP meta_title, DROP meta_description, DROP primary_keyword, DROP secondary_keywords, DROP faq, DROP internal_links, DROP external_links, DROP reading_time, DROP canonical_url, DROP og_image, DROP scheduled_at, DROP representation_id');
}
}