migrations/Version20251022100000.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.  * Complete multi-tenancy migration - Simple and reliable version.
  8.  * Adds client_id to all entities and makes created/modified nullable.
  9.  */
  10. final class Version20251022100000 extends AbstractMigration
  11. {
  12.     public function getDescription(): string
  13.     {
  14.         return 'Add client_id to all entities and make created/modified nullable';
  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 foreignKeyExists(string $tablestring $fkName): bool
  29.     {
  30.         $result $this->connection->fetchOne(
  31.             "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
  32.              WHERE TABLE_SCHEMA = DATABASE() 
  33.              AND TABLE_NAME = ? 
  34.              AND CONSTRAINT_NAME = ?
  35.              AND CONSTRAINT_TYPE = 'FOREIGN KEY'",
  36.             [$table$fkName]
  37.         );
  38.         
  39.         return $result 0;
  40.     }
  41.     private function indexExists(string $tablestring $indexName): bool
  42.     {
  43.         $result $this->connection->fetchOne(
  44.             "SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS 
  45.              WHERE TABLE_SCHEMA = DATABASE() 
  46.              AND TABLE_NAME = ? 
  47.              AND INDEX_NAME = ?",
  48.             [$table$indexName]
  49.         );
  50.         
  51.         return $result 0;
  52.     }
  53.     public function up(Schema $schema): void
  54.     {
  55.         // ============================================================
  56.         // Add client_id columns
  57.         // ============================================================
  58.         
  59.         $tables = [
  60.             'attachment''cart_item''ckimage''course_image''course_occurrence',
  61.             'course_occurrence_time''course_subscription_booking''course_text',
  62.             'customer_document''customer_history_entry''customer_order_item',
  63.             'customer_order_item_person''invoice''invoice_item''invoice_item_attendees',
  64.             'invoice_payment''invoice_reminder''manual_newsletter''newsletter',
  65.             'person''presence_reason''protocol_entry''provider''speaker',
  66.             'speaker_image''speaker_text''tags''textblocks''venue_document',
  67.             'venue_image''venue_room''wait_item'
  68.         ];
  69.         foreach ($tables as $table) {
  70.             if (!$this->columnExists($table'client_id')) {
  71.                 $this->addSql("ALTER TABLE $table ADD client_id INT DEFAULT NULL");
  72.             }
  73.         }
  74.         // ============================================================
  75.         // Make created/modified nullable in all tables
  76.         // ============================================================
  77.         
  78.         $entityTables = [
  79.             'attachment''cart''cart_item''category''ckimage''client_config',
  80.             'course''course_data''course_field''course_image''course_occurrence',
  81.             'course_series''course_subscription''course_subscription_booking',
  82.             'course_text''course_type''customer_document''customer_history_entry',
  83.             'customer_order''customer_order_item''customer_order_item_person',
  84.             'email_history_entry''invoice''invoice_item''invoice_payment',
  85.             'invoice_reminder''person''presence''presence_reason''protocol_entry',
  86.             'provider''search_index_entry''speaker''speaker_image''speaker_text',
  87.             'tags''textblocks''venue''venue_document''venue_image''venue_room''wait_item'
  88.         ];
  89.         foreach ($entityTables as $table) {
  90.             if ($this->columnExists($table'created')) {
  91.                 $this->addSql("ALTER TABLE $table MODIFY created DATETIME DEFAULT NULL");
  92.             }
  93.             if ($this->columnExists($table'modified')) {
  94.                 $this->addSql("ALTER TABLE $table MODIFY modified DATETIME DEFAULT NULL");
  95.             }
  96.         }
  97.         // ============================================================
  98.         // Add Foreign Keys and Indexes
  99.         // ============================================================
  100.         
  101.         $constraints = [
  102.             'attachment' => 'FK_795FD9BB19EB6921',
  103.             'cart_item' => 'FK_F0FE252719EB6921',
  104.             'ckimage' => 'FK_5A0E314919EB6921',
  105.             'course_image' => 'FK_3E47454719EB6921',
  106.             'course_occurrence' => 'FK_9A13519919EB6921',
  107.             'course_occurrence_time' => 'FK_A4E42A7319EB6921',
  108.             'course_subscription_booking' => 'FK_CSB19EB6921',
  109.             'course_text' => 'FK_9E5A7BF19EB6921',
  110.             'customer_document' => 'FK_7C3547E219EB6921',
  111.             'customer_history_entry' => 'FK_48E0B46219EB6921',
  112.             'customer_order_item' => 'FK_4D39F7F419EB6921',
  113.             'customer_order_item_person' => 'FK_9C6D81F519EB6921',
  114.             'invoice' => 'FK_9065174419EB6921',
  115.             'invoice_item' => 'FK_1DDE477B19EB6921',
  116.             'invoice_item_attendees' => 'FK_IIA19EB6921',
  117.             'invoice_payment' => 'FK_1850519419EB6921',
  118.             'invoice_reminder' => 'FK_5F1F151819EB6921',
  119.             'manual_newsletter' => 'FK_76687F0719EB6921',
  120.             'newsletter' => 'FK_7E8585C819EB6921',
  121.             'person' => 'FK_34DCD17619EB6921',
  122.             'presence_reason' => 'FK_D629391C19EB6921',
  123.             'protocol_entry' => 'FK_E545771019EB6921',
  124.             'provider' => 'FK_92C4739C19EB6921',
  125.             'speaker' => 'FK_7B85DB6119EB6921',
  126.             'speaker_image' => 'FK_F0ABBBCC19EB6921',
  127.             'speaker_text' => 'FK_189CCEEF19EB6921',
  128.             'tags' => 'FK_6FBC942619EB6921',
  129.             'textblocks' => 'FK_1261C3B919EB6921',
  130.             'venue_document' => 'FK_B9B2BD5219EB6921',
  131.             'venue_image' => 'FK_1D86098819EB6921',
  132.             'venue_room' => 'FK_C4B95C3319EB6921',
  133.             'wait_item' => 'FK_640BFE6E19EB6921',
  134.         ];
  135.         foreach ($constraints as $table => $fk) {
  136.             if ($this->columnExists($table'client_id')) {
  137.                 // Add foreign key only if it doesn't exist
  138.                 if (!$this->foreignKeyExists($table$fk)) {
  139.                     $this->addSql("ALTER TABLE $table ADD CONSTRAINT $fk FOREIGN KEY (client_id) REFERENCES client (id)");
  140.                 }
  141.                 // Add index only if it doesn't exist
  142.                 if (!$this->indexExists($table$fk)) {
  143.                     $this->addSql("CREATE INDEX $fk ON $table (client_id)");
  144.                 }
  145.             }
  146.         }
  147.         // Other fixes
  148.         if ($this->columnExists('user''person_id')) {
  149.             $this->addSql('ALTER TABLE user DROP person_id');
  150.         }
  151.     }
  152.     public function down(Schema $schema): void
  153.     {
  154.         // Remove foreign keys and columns
  155.         $constraints = [
  156.             'attachment' => 'FK_795FD9BB19EB6921',
  157.             'cart_item' => 'FK_F0FE252719EB6921',
  158.             'ckimage' => 'FK_5A0E314919EB6921',
  159.             'course_image' => 'FK_3E47454719EB6921',
  160.             'course_occurrence' => 'FK_9A13519919EB6921',
  161.             'course_occurrence_time' => 'FK_A4E42A7319EB6921',
  162.             'course_subscription_booking' => 'FK_CSB19EB6921',
  163.             'course_text' => 'FK_9E5A7BF19EB6921',
  164.             'customer_document' => 'FK_7C3547E219EB6921',
  165.             'customer_history_entry' => 'FK_48E0B46219EB6921',
  166.             'customer_order_item' => 'FK_4D39F7F419EB6921',
  167.             'customer_order_item_person' => 'FK_9C6D81F519EB6921',
  168.             'invoice' => 'FK_9065174419EB6921',
  169.             'invoice_item' => 'FK_1DDE477B19EB6921',
  170.             'invoice_item_attendees' => 'FK_IIA19EB6921',
  171.             'invoice_payment' => 'FK_1850519419EB6921',
  172.             'invoice_reminder' => 'FK_5F1F151819EB6921',
  173.             'manual_newsletter' => 'FK_76687F0719EB6921',
  174.             'newsletter' => 'FK_7E8585C819EB6921',
  175.             'person' => 'FK_34DCD17619EB6921',
  176.             'presence_reason' => 'FK_D629391C19EB6921',
  177.             'protocol_entry' => 'FK_E545771019EB6921',
  178.             'provider' => 'FK_92C4739C19EB6921',
  179.             'speaker' => 'FK_7B85DB6119EB6921',
  180.             'speaker_image' => 'FK_F0ABBBCC19EB6921',
  181.             'speaker_text' => 'FK_189CCEEF19EB6921',
  182.             'tags' => 'FK_6FBC942619EB6921',
  183.             'textblocks' => 'FK_1261C3B919EB6921',
  184.             'venue_document' => 'FK_B9B2BD5219EB6921',
  185.             'venue_image' => 'FK_1D86098819EB6921',
  186.             'venue_room' => 'FK_C4B95C3319EB6921',
  187.             'wait_item' => 'FK_640BFE6E19EB6921',
  188.         ];
  189.         foreach ($constraints as $table => $fk) {
  190.             $this->addSql("ALTER TABLE $table DROP FOREIGN KEY $fk");
  191.             $this->addSql("DROP INDEX $fk ON $table");
  192.             $this->addSql("ALTER TABLE $table DROP client_id");
  193.         }
  194.     }
  195. }