- 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.
46 lines
2.8 KiB
PHP
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');
|
|
}
|
|
}
|