migrations/Version20251022101000.php line 1

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace DoctrineMigrations;
  4. use Doctrine\DBAL\Schema\Schema;
  5. use Doctrine\Migrations\AbstractMigration;
  6. /**
  7.  * Add client_id to remaining tables (join tables, provider tables, OAuth tables).
  8.  * Positions client_id as the second column (after id).
  9.  */
  10. final class Version20251022101000 extends AbstractMigration
  11. {
  12.     public function getDescription(): string
  13.     {
  14.         return 'Add client_id to all remaining tables and position it after id column';
  15.     }
  16.     private function columnExists(string $tablestring $column): bool
  17.     {
  18.         $result $this->connection->fetchOne(
  19.             "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS 
  20.              WHERE TABLE_SCHEMA = DATABASE() 
  21.              AND TABLE_NAME = ? 
  22.              AND COLUMN_NAME = ?",
  23.             [$table$column]
  24.         );
  25.         
  26.         return $result 0;
  27.     }
  28.     private function tableExists(string $table): bool
  29.     {
  30.         $result $this->connection->fetchOne(
  31.             "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES 
  32.              WHERE TABLE_SCHEMA = DATABASE() 
  33.              AND TABLE_NAME = ?",
  34.             [$table]
  35.         );
  36.         
  37.         return $result 0;
  38.     }
  39.     private function foreignKeyExists(string $tablestring $fkName): bool
  40.     {
  41.         $result $this->connection->fetchOne(
  42.             "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
  43.              WHERE TABLE_SCHEMA = DATABASE() 
  44.              AND TABLE_NAME = ? 
  45.              AND CONSTRAINT_NAME = ?
  46.              AND CONSTRAINT_TYPE = 'FOREIGN KEY'",
  47.             [$table$fkName]
  48.         );
  49.         
  50.         return $result 0;
  51.     }
  52.     public function up(Schema $schema): void
  53.     {
  54.         // ============================================================
  55.         // Tables to update with client_id
  56.         // Excluding: client (is the client table itself), 
  57.         //            doctrine_migration_versions (system table)
  58.         // ============================================================
  59.         
  60.         $tablesToUpdate = [
  61.             // Join tables
  62.             'cart_item_person',
  63.             'course_occurrence_speaker',
  64.             'email_history_entry_person',
  65.             'person_course_occurrence',
  66.             
  67.             // Provider join tables
  68.             'course_provider',
  69.             'occurrence_provider',
  70.             'speaker_provider',
  71.             'venue_provider',
  72.             
  73.             // Tags join table
  74.             'tags_person',
  75.             
  76.             // OAuth tables
  77.             'oauth_client',
  78.             'oauth_auth_code',
  79.             'oauth2_access_token',
  80.             'oauth2_authorization_code',
  81.             'oauth2_refresh_token',
  82.         ];
  83.         foreach ($tablesToUpdate as $table) {
  84.             // Skip if table doesn't exist
  85.             if (!$this->tableExists($table)) {
  86.                 continue;
  87.             }
  88.             // Add client_id column if it doesn't exist
  89.             if (!$this->columnExists($table'client_id')) {
  90.                 // Add column positioned after id
  91.                 if ($this->columnExists($table'id')) {
  92.                     $this->addSql("ALTER TABLE $table ADD client_id INT DEFAULT NULL AFTER id");
  93.                 } else {
  94.                     // If no id column, add as first column
  95.                     $this->addSql("ALTER TABLE $table ADD client_id INT DEFAULT NULL FIRST");
  96.                 }
  97.             }
  98.         }
  99.         // ============================================================
  100.         // Add Foreign Keys and Indexes
  101.         // ============================================================
  102.         
  103.         $constraints = [
  104.             'cart_item_person' => 'FK_CIP19EB6921',
  105.             'course_occurrence_speaker' => 'FK_COS19EB6921',
  106.             'email_history_entry_person' => 'FK_EHEP19EB6921',
  107.             'person_course_occurrence' => 'FK_PCO19EB6921',
  108.             'course_provider' => 'FK_CP19EB6921',
  109.             'occurrence_provider' => 'FK_OP19EB6921',
  110.             'speaker_provider' => 'FK_SP19EB6921',
  111.             'venue_provider' => 'FK_VP19EB6921',
  112.             'tags_person' => 'FK_TP19EB6921',
  113.             'oauth_client' => 'FK_OC19EB6921',
  114.             'oauth_auth_code' => 'FK_OAC19EB6921',
  115.             'oauth2_access_token' => 'FK_O2AT19EB6921',
  116.             'oauth2_authorization_code' => 'FK_O2AC19EB6921',
  117.             'oauth2_refresh_token' => 'FK_O2RT19EB6921',
  118.         ];
  119.         foreach ($constraints as $table => $fkName) {
  120.             // Skip if table doesn't exist
  121.             if (!$this->tableExists($table)) {
  122.                 continue;
  123.             }
  124.             // Only add FK and index if column exists and FK doesn't exist yet
  125.             if ($this->columnExists($table'client_id') && !$this->foreignKeyExists($table$fkName)) {
  126.                 try {
  127.                     $this->addSql("ALTER TABLE $table ADD CONSTRAINT $fkName FOREIGN KEY (client_id) REFERENCES client (id)");
  128.                     $this->addSql("CREATE INDEX $fkName ON $table (client_id)");
  129.                 } catch (\Exception $e) {
  130.                     // Skip if there's an error (e.g., constraint already exists with different name)
  131.                 }
  132.             }
  133.         }
  134.         // ============================================================
  135.         // Special case: search_index_entry - rename clientId to client_id
  136.         // ============================================================
  137.         
  138.         if ($this->tableExists('search_index_entry')) {
  139.             if ($this->columnExists('search_index_entry''clientId') && !$this->columnExists('search_index_entry''client_id')) {
  140.                 $this->addSql("ALTER TABLE search_index_entry CHANGE clientId client_id INT NOT NULL FIRST");
  141.             } elseif ($this->columnExists('search_index_entry''client_id')) {
  142.                 // Position it first if already renamed
  143.                 $this->addSql("ALTER TABLE search_index_entry MODIFY client_id INT NOT NULL FIRST");
  144.             }
  145.         }
  146.     }
  147.     public function down(Schema $schema): void
  148.     {
  149.         // Rollback: Remove client_id from tables
  150.         $tables = [
  151.             'cart_item_person''course_occurrence_speaker''email_history_entry_person',
  152.             'person_course_occurrence''course_provider''occurrence_provider',
  153.             'speaker_provider''venue_provider''tags_person''oauth_client',
  154.             'oauth_auth_code''oauth2_access_token''oauth2_authorization_code',
  155.             'oauth2_refresh_token'
  156.         ];
  157.         $constraints = [
  158.             'cart_item_person' => 'FK_CIP19EB6921',
  159.             'course_occurrence_speaker' => 'FK_COS19EB6921',
  160.             'email_history_entry_person' => 'FK_EHEP19EB6921',
  161.             'person_course_occurrence' => 'FK_PCO19EB6921',
  162.             'course_provider' => 'FK_CP19EB6921',
  163.             'occurrence_provider' => 'FK_OP19EB6921',
  164.             'speaker_provider' => 'FK_SP19EB6921',
  165.             'venue_provider' => 'FK_VP19EB6921',
  166.             'tags_person' => 'FK_TP19EB6921',
  167.             'oauth_client' => 'FK_OC19EB6921',
  168.             'oauth_auth_code' => 'FK_OAC19EB6921',
  169.             'oauth2_access_token' => 'FK_O2AT19EB6921',
  170.             'oauth2_authorization_code' => 'FK_O2AC19EB6921',
  171.             'oauth2_refresh_token' => 'FK_O2RT19EB6921',
  172.         ];
  173.         foreach ($tables as $table) {
  174.             if ($this->tableExists($table) && $this->columnExists($table'client_id')) {
  175.                 $fkName $constraints[$table];
  176.                 
  177.                 // Drop FK if exists
  178.                 if ($this->foreignKeyExists($table$fkName)) {
  179.                     $this->addSql("ALTER TABLE $table DROP FOREIGN KEY $fkName");
  180.                     $this->addSql("DROP INDEX $fkName ON $table");
  181.                 }
  182.                 
  183.                 // Drop column
  184.                 $this->addSql("ALTER TABLE $table DROP client_id");
  185.             }
  186.         }
  187.         // Reverse search_index_entry
  188.         if ($this->tableExists('search_index_entry') && $this->columnExists('search_index_entry''client_id')) {
  189.             $this->addSql("ALTER TABLE search_index_entry CHANGE client_id clientId INT NOT NULL FIRST");
  190.         }
  191.     }
  192. }