<?php namespace DatabaseHelper; use DatabaseHelper\enums\Propagation; use DatabaseHelper\enums\Type; use InvalidArgumentException; class Migration { protected Schema $table; protected array $columnsToAdd = []; protected array $columnsToModify = []; protected array $columnsToDrop = []; protected array $primaryKey = null; protected array $foreignKeysToAdd = []; protected array $foreignKeysToDrop = []; public function __construct(Schema $table) { $this->table = $table->copy(); } public function addColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration { $this->table->columns[$name] = [ 'name' => $name, 'type' => $type, 'default' => $default, 'isNullable' => $isNullable, 'isUnique' => $isUnique ]; $this->columnsToAdd[] = $name; return $this; } public function modifyColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration { if (!isset($this->table->columns[$name])) { throw new InvalidArgumentException("Column $name does not exist."); } $this->table->columns[$name] = [ 'name' => $name, 'type' => $type, 'default' => $default, 'isNullable' => $isNullable, 'isUnique' => $isUnique ]; $this->columnsToModify[] = $name; return $this; } public function dropColumn(string $name): Migration { if (!isset($this->table->columns[$name])) { throw new InvalidArgumentException("Column $name does not exist."); } unset($this->table->columns[$name]); $this->columnsToDrop[] = $name; return $this; } public function changePrimaryKey(string $name, bool $autoInc = false): Migration { if (!isset($this->table->columns[$name])) { throw new InvalidArgumentException("Column $name does not exist."); } $this->table->primaryKey = [ 'name' => $name, 'autoInc' => $autoInc ]; $this->primaryKey = $name; return $this; } public function addForeignKey(string $column, string $referencedTable, string $referencedColumn, Propagation $onDelete, Propagation $onUpdate): Migration { if (!isset($this->table->columns[$column])) { throw new InvalidArgumentException("Column $column does not exist."); } $this->table->foreignKeys[$column] = [ 'referencedTable' => $referencedTable, 'referencedColumn' => $referencedColumn, 'onDelete' => $onDelete, 'onUpdate' => $onUpdate ]; $this->foreignKeysToAdd[] = $column; return $this; } public function dropForeignKey(string $name): Migration { if (!isset($this->table->foreignKeys[$name])) { throw new InvalidArgumentException("Foreign key $name does not exist."); } unset($this->table->foreignKeys[$name]); $this->foreignKeysToDrop[] = $name; return $this; } public function toSql(): string { $sql = "ALTER TABLE `{$this->table->name}` "; $statements = []; foreach ($this->columnsToAdd as $name) { $col = $this->table->columns[$name]; $statements[] = "ADD COLUMN `{$col['name']}` {$col['type']->toString()}" . ($col['isNullable'] ? "" : " NOT NULL") . ($col['isUnique'] ? " UNIQUE" : "") . ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : ""); } foreach ($this->columnsToModify as $name) { $col = $this->table->columns[$name]; $statements[] = "MODIFY COLUMN `{$col['name']}` {$col['type']->toString()}" . ($col['isNullable'] ? "" : " NOT NULL") . ($col['isUnique'] ? " UNIQUE" : "") . ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : ""); } foreach ($this->columnsToDrop as $name) { $statements[] = "DROP COLUMN `$name`"; } foreach ($this->foreignKeysToDrop as $name) { $statements[] = "DROP FOREIGN KEY `$name`"; } foreach ($this->foreignKeysToAdd as $column) { $fk = $this->table->foreignKeys[$column]; $statements[] = "ADD CONSTRAINT `fk_{$column}` FOREIGN KEY (`$column`) REFERENCES `{$fk['referencedTable']}` (`{$fk['referencedColumn']}`) ON DELETE {$fk['onDelete']->toString()} ON UPDATE {$fk['onUpdate']->toString()}"; } return $sql . implode(", ", $statements) . ";"; } public function drop(): null { } public function migrate(): Schema { global $wpdb; $sql = $this->toSql(); $wpdb->query($sql); return $this->table; } }