<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Final schema cleanup: Fix indexes and foreign keys, keep created/client_id nullable.
*/
final class Version20251022102000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Final schema cleanup - fix indexes and FK, keep created/client_id nullable';
}
public function up(Schema $schema): void
{
// ============================================================
// Remove client_id from join tables and OAuth tables (correct)
// ============================================================
$this->addSql('ALTER TABLE cart_item_person DROP COLUMN IF EXISTS client_id');
$this->addSql('ALTER TABLE email_history_entry_person DROP COLUMN IF EXISTS client_id');
$this->addSql('ALTER TABLE oauth2_authorization_code DROP COLUMN IF EXISTS client_id');
$this->addSql('ALTER TABLE oauth2_refresh_token DROP COLUMN IF EXISTS client_id');
$this->addSql('ALTER TABLE oauth2_access_token DROP COLUMN IF EXISTS client_id');
$this->addSql('ALTER TABLE oauth_auth_code DROP COLUMN IF EXISTS client_id');
// ============================================================
// Fix Foreign Keys and Indexes (keep client_id as nullable!)
// ============================================================
// presence_reason - Drop FK first, then indexes
$this->connection->executeStatement("
SET @fk = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'presence_reason'
AND COLUMN_NAME = 'client_id' AND REFERENCED_TABLE_NAME IS NOT NULL LIMIT 1);
SET @sql = IF(@fk IS NOT NULL, CONCAT('ALTER TABLE presence_reason DROP FOREIGN KEY ', @fk), 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Now drop indexes
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'presence_reason'
AND INDEX_NAME = 'IDX_PR19EB6921');
SET @sql = IF(@idx > 0, 'DROP INDEX IDX_PR19EB6921 ON presence_reason', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'presence_reason'
AND INDEX_NAME = 'FK_D629391C19EB6921');
SET @sql = IF(@idx > 0, 'DROP INDEX FK_D629391C19EB6921 ON presence_reason', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Create new index and FK
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'presence_reason'
AND INDEX_NAME = 'IDX_D629391C19EB6921');
SET @sql = IF(@idx = 0, 'CREATE INDEX IDX_D629391C19EB6921 ON presence_reason (client_id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
$this->connection->executeStatement("
SET @fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'presence_reason'
AND CONSTRAINT_NAME = 'FK_D629391C19EB6921' AND REFERENCED_TABLE_NAME IS NOT NULL);
SET @sql = IF(@fk = 0, 'ALTER TABLE presence_reason ADD CONSTRAINT FK_D629391C19EB6921 FOREIGN KEY (client_id) REFERENCES client (id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// ckimage - Drop FK first
$this->connection->executeStatement("
SET @fk = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ckimage'
AND COLUMN_NAME = 'client_id' AND REFERENCED_TABLE_NAME IS NOT NULL LIMIT 1);
SET @sql = IF(@fk IS NOT NULL, CONCAT('ALTER TABLE ckimage DROP FOREIGN KEY ', @fk), 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Now drop index
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ckimage'
AND INDEX_NAME = 'FK_5A0E314919EB6921');
SET @sql = IF(@idx > 0, 'DROP INDEX FK_5A0E314919EB6921 ON ckimage', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// cart_item - Drop FK first
$this->connection->executeStatement("
SET @fk = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cart_item'
AND COLUMN_NAME = 'client_id' AND REFERENCED_TABLE_NAME IS NOT NULL LIMIT 1);
SET @sql = IF(@fk IS NOT NULL, CONCAT('ALTER TABLE cart_item DROP FOREIGN KEY ', @fk), 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Now drop index
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cart_item'
AND INDEX_NAME = 'FK_F0FE252719EB6921');
SET @sql = IF(@idx > 0, 'DROP INDEX FK_F0FE252719EB6921 ON cart_item', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// speaker_provider
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_provider'
AND INDEX_NAME = 'IDX_17A0F10619EB6921');
SET @sql = IF(@idx = 0, 'CREATE INDEX IDX_17A0F10619EB6921 ON speaker_provider (client_id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
$this->connection->executeStatement("
SET @fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_provider'
AND CONSTRAINT_NAME = 'FK_17A0F10619EB6921' AND REFERENCED_TABLE_NAME IS NOT NULL);
SET @sql = IF(@fk = 0, 'ALTER TABLE speaker_provider ADD CONSTRAINT FK_17A0F10619EB6921 FOREIGN KEY (client_id) REFERENCES client (id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// speaker_text - Drop FK first
$this->connection->executeStatement("
SET @fk = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_text'
AND COLUMN_NAME = 'client_id' AND REFERENCED_TABLE_NAME IS NOT NULL LIMIT 1);
SET @sql = IF(@fk IS NOT NULL, CONCAT('ALTER TABLE speaker_text DROP FOREIGN KEY ', @fk), 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Drop old index
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_text'
AND INDEX_NAME = 'fk_189cceef19eb6921');
SET @sql = IF(@idx > 0, 'DROP INDEX fk_189cceef19eb6921 ON speaker_text', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Create new index and FK
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_text'
AND INDEX_NAME = 'IDX_189CCEEF19EB6921');
SET @sql = IF(@idx = 0, 'CREATE INDEX IDX_189CCEEF19EB6921 ON speaker_text (client_id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
$this->connection->executeStatement("
SET @fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'speaker_text'
AND CONSTRAINT_NAME = 'FK_189CCEEF19EB6921' AND REFERENCED_TABLE_NAME IS NOT NULL);
SET @sql = IF(@fk = 0, 'ALTER TABLE speaker_text ADD CONSTRAINT FK_189CCEEF19EB6921 FOREIGN KEY (client_id) REFERENCES client (id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// client_config - Drop FK first
$this->connection->executeStatement("
SET @fk = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'client_config'
AND COLUMN_NAME = 'client_id' AND REFERENCED_TABLE_NAME IS NOT NULL LIMIT 1);
SET @sql = IF(@fk IS NOT NULL, CONCAT('ALTER TABLE client_config DROP FOREIGN KEY ', @fk), 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Drop old index
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'client_config'
AND INDEX_NAME = 'idx_812c64cfea1ce9be');
SET @sql = IF(@idx > 0, 'DROP INDEX idx_812c64cfea1ce9be ON client_config', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// Create new index and FK
$this->connection->executeStatement("
SET @idx = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'client_config'
AND INDEX_NAME = 'IDX_812C64CF19EB6921');
SET @sql = IF(@idx = 0, 'CREATE INDEX IDX_812C64CF19EB6921 ON client_config (client_id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
$this->connection->executeStatement("
SET @fk = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'client_config'
AND CONSTRAINT_NAME = 'FK_812C64CF19EB6921' AND REFERENCED_TABLE_NAME IS NOT NULL);
SET @sql = IF(@fk = 0, 'ALTER TABLE client_config ADD CONSTRAINT FK_812C64CF19EB6921 FOREIGN KEY (client_id) REFERENCES client (id)', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt;
");
// ============================================================
// IMPORTANT: Keep created and client_id as NULLABLE
// We do NOT set them to NOT NULL until data is assigned!
// ============================================================
// Ensure all created/modified columns are nullable
$tables = [
'invoice_reminder', 'ckimage', 'course_data', 'cart_item', 'speaker_text',
'cart', 'presence', 'client_config', 'email_history_entry'
];
foreach ($tables as $table) {
$this->addSql("ALTER TABLE $table MODIFY created DATETIME DEFAULT NULL");
$this->addSql("ALTER TABLE $table MODIFY modified DATETIME DEFAULT NULL");
}
// Ensure client_id columns are nullable
$this->addSql('ALTER TABLE cart MODIFY client_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE presence MODIFY client_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE email_history_entry MODIFY client_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE course_data MODIFY client_id INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
// Rollback not needed - this is a cleanup migration
}
}