# Migration Helper Examples This document shows how to use the new `MigrationHelper` service to simplify migration code and explains the improved migration generation system. ## Overview The `MigrationHelper` provides a simplified API for common migration operations without requiring abstract classes. It uses composition and follows framework principles. The improved `MigrationGenerator` now: - Automatically determines namespace from file path using `PathProvider` - Uses `PhpNamespace` Value Object for type-safe namespace handling - Automatically detects if migration should be `SafelyReversible` based on name patterns - Generates cleaner code using `MigrationHelper` by default ## Basic Usage ### Before (Old Way) ```php final readonly class CreateUsersTable implements Migration { public function up(ConnectionInterface $connection): void { $schema = new Schema($connection); $schema->createIfNotExists('users', function (Blueprint $table) { $table->ulid('ulid')->primary(); $table->string('name', 255); $table->timestamps(); }); $schema->execute(); } public function getVersion(): MigrationVersion { return MigrationVersion::fromTimestamp('2024_01_15_000001'); } public function getDescription(): string { return 'Create Users Table'; } } ``` ### After (New Way with Helper) ```php final readonly class CreateUsersTable implements Migration, SafelyReversible { public function up(ConnectionInterface $connection): void { $helper = new MigrationHelper($connection); $helper->createTable('users', function (Blueprint $table) { $table->ulid('ulid')->primary(); $table->string('name', 255); $table->timestamps(); }); } public function down(ConnectionInterface $connection): void { $helper = new MigrationHelper($connection); $helper->dropTable('users'); } public function getVersion(): MigrationVersion { return MigrationVersion::fromTimestamp('2024_01_15_000001'); } public function getDescription(): string { return 'Create Users Table'; } } ``` ## Available Helper Methods ### Creating Tables ```php $helper = new MigrationHelper($connection); $helper->createTable('users', function (Blueprint $table) { $table->ulid('ulid')->primary(); $table->string('name', 255); $table->string('email', 255)->unique(); $table->timestamps(); }); ``` ### Dropping Tables ```php $helper->dropTable('users'); ``` ### Adding Columns ```php // Simple column $helper->addColumn('users', 'phone', 'string', ['length' => 20]); // Column with options $helper->addColumn('users', 'age', 'integer', [ 'nullable' => false, 'default' => 0 ]); // Decimal column $helper->addColumn('orders', 'total', 'decimal', [ 'precision' => 10, 'scale' => 2, 'nullable' => false ]); ``` ### Adding Indexes ```php // Simple index $helper->addIndex('users', ['email']); // Named index $helper->addIndex('users', ['name', 'email'], 'idx_users_name_email'); // Unique index $helper->addUniqueIndex('users', ['email'], 'uk_users_email'); ``` ### Dropping Columns ```php $helper->dropColumn('users', 'phone'); ``` ### Renaming Tables ```php $helper->renameTable('old_table_name', 'new_table_name'); ``` ## Advanced: Using Schema Directly For complex operations, you can still use Schema directly: ```php public function up(ConnectionInterface $connection): void { $helper = new MigrationHelper($connection); $schema = $helper->schema(); // Complex operations $schema->table('users', function (Blueprint $table) { $table->dropColumn('old_column'); $table->renameColumn('old_name', 'new_name'); $table->addColumn('new_column', 'string', 255); }); $schema->execute(); } ``` ## Benefits 1. **Less Boilerplate**: No need to manually create Schema and call execute() 2. **Consistent API**: All helper methods follow the same pattern 3. **Type Safe**: Uses Value Objects and proper types 4. **Composable**: Can mix helper methods with direct Schema usage 5. **No Inheritance**: Uses composition, follows framework principles ## Migration Generator The `MigrationGenerator` has been significantly improved with automatic namespace detection and smarter code generation. ### Automatic Namespace Detection The generator uses `PathProvider` to automatically determine the correct namespace from the file path, making it work with any project structure: ```php // When generating: php console.php make:migration CreateUsersTable User // Path: src/Domain/User/Migrations/CreateUsersTable.php // Namespace automatically determined: App\Domain\User\Migrations ``` **How it works:** 1. `PathProvider` reads `composer.json` to understand PSR-4 autoloading rules 2. The migration directory path is analyzed 3. `PhpNamespace` Value Object is created from the path 4. Fallback to default structure if path doesn't match PSR-4 rules **Benefits:** - Works with any namespace structure configured in `composer.json` - No hardcoded namespace assumptions - Type-safe namespace handling via `PhpNamespace` Value Object - Automatically adapts to project structure changes ### Automatic SafelyReversible Detection The generator analyzes migration names to determine if they should implement `SafelyReversible`: **Safe patterns (automatically reversible):** - `Create*` - Creating tables can be rolled back - `Add*` - Adding columns/indexes can be removed - `Index*` - Index operations are reversible - `Constraint*` - Constraints can be dropped - `Rename*` - Renaming can be reversed **Unsafe patterns (forward-only):** - `Drop*` - Dropping tables/columns loses data - `Delete*` - Data deletion cannot be reversed - `Remove*` - Removing columns loses data - `Truncate*` - Truncating loses all data - `Alter*Type` - Type changes may lose data **Example:** ```bash # Creates SafelyReversible migration php console.php make:migration CreateUsersTable User # Creates forward-only migration php console.php make:migration DropOldColumns User ``` ### Generated Code Examples **Create Table Migration (SafelyReversible):** ```bash php console.php make:migration CreateUsersTable User ``` Generates: ```php createTable('users', function($table) { // $table->ulid('ulid')->primary(); // $table->string('name', 255); // $table->timestamps(); // }); } public function down(ConnectionInterface $connection): void { $helper = new MigrationHelper($connection); $helper->dropTable('users'); // Auto-generated from name } public function getVersion(): MigrationVersion { return MigrationVersion::fromTimestamp('2024_01_15_120000'); } public function getDescription(): string { return 'Create Users Table'; } } ``` **Forward-Only Migration:** ```bash php console.php make:migration DropOldColumns User ``` Generates: ```php dropColumn('users', 'old_column'); } // No down() method - forward-only migration public function getVersion(): MigrationVersion { return MigrationVersion::fromTimestamp('2024_01_15_120001'); } public function getDescription(): string { return 'Drop Old Columns'; } } ``` ### Custom Namespace Structures The generator works with any namespace structure defined in `composer.json`: ```json { "autoload": { "psr-4": { "App\\": "src/", "Custom\\Namespace\\": "custom/path/" } } } ``` If you generate a migration in `custom/path/Migrations/`, the namespace will automatically be `Custom\Namespace\Migrations`. ### MigrationMetadata Value Object For advanced use cases, you can use `MigrationMetadata` to work with migration metadata: ```php use App\Framework\Database\Migration\ValueObjects\MigrationMetadata; use App\Framework\Core\ValueObjects\PhpNamespace; $namespace = PhpNamespace::fromString('App\Domain\User\Migrations'); $metadata = MigrationMetadata::create( version: MigrationVersion::fromTimestamp('2024_01_15_120000'), description: 'Create Users Table', namespace: $namespace, domain: 'User', author: 'John Doe' ); // Metadata automatically extracts domain from namespace // $metadata->domain === 'User' ``` ## Best Practices 1. **Use MigrationHelper for common operations** - Reduces boilerplate 2. **Let generator detect SafelyReversible** - Don't manually add it unless needed 3. **Trust PathProvider for namespaces** - It handles PSR-4 correctly 4. **Use PhpNamespace Value Objects** - Type-safe namespace operations 5. **Keep migrations simple** - Use helper methods, fall back to Schema for complex cases