fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
368
docs/claude/migration-helper-examples.md
Normal file
368
docs/claude/migration-helper-examples.md
Normal file
@@ -0,0 +1,368 @@
|
||||
# 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
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Domain\User\Migrations;
|
||||
|
||||
use App\Framework\Database\ConnectionInterface;
|
||||
use App\Framework\Database\Migration\Migration;
|
||||
use App\Framework\Database\Migration\MigrationVersion;
|
||||
use App\Framework\Database\Migration\Services\MigrationHelper;
|
||||
use App\Framework\Database\Migration\SafelyReversible;
|
||||
|
||||
final readonly class CreateUsersTable implements Migration, SafelyReversible
|
||||
{
|
||||
public function up(ConnectionInterface $connection): void
|
||||
{
|
||||
$helper = new MigrationHelper($connection);
|
||||
|
||||
// TODO: Implement your migration here
|
||||
// Example:
|
||||
// $helper->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
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Domain\User\Migrations;
|
||||
|
||||
use App\Framework\Database\ConnectionInterface;
|
||||
use App\Framework\Database\Migration\Migration;
|
||||
use App\Framework\Database\Migration\MigrationVersion;
|
||||
use App\Framework\Database\Migration\Services\MigrationHelper;
|
||||
|
||||
final readonly class DropOldColumns implements Migration
|
||||
{
|
||||
public function up(ConnectionInterface $connection): void
|
||||
{
|
||||
$helper = new MigrationHelper($connection);
|
||||
|
||||
// TODO: Implement your migration here
|
||||
// Example:
|
||||
// $helper->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
|
||||
|
||||
Reference in New Issue
Block a user