Files
project-replica/app/Http/Controllers/MigrationScheduleController.php
2026-03-23 00:51:38 +09:00

232 lines
9.3 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\MigrationSchedule;
use App\Models\SourceDatabase;
use App\Models\TargetDatabase;
use App\Models\Table;
use App\Models\MigrationRun;
use App\Jobs\RunMigrationJob;
use Illuminate\Http\Request;
use Inertia\Inertia;
class MigrationScheduleController extends Controller
{
public function index()
{
$schedules = MigrationSchedule::with(['sourceDatabase', 'targetDatabase'])
->withCount('migrationRuns')
->get();
return Inertia::render('Migrations/Index', [
'schedules' => $schedules,
]);
}
public function create()
{
$sourceDatabases = SourceDatabase::where('is_active', true)->get();
$targetDatabases = TargetDatabase::where('is_active', true)->get();
$tables = Table::with('sourceDatabase')->get()->groupBy('source_database_id');
return Inertia::render('Migrations/ScheduleForm', [
'schedule' => null,
'sourceDatabases' => $sourceDatabases,
'targetDatabases' => $targetDatabases,
'tables' => $tables,
]);
}
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'source_database_id' => 'required|exists:source_databases,id',
'target_database_id' => 'required|exists:target_databases,id',
'tables' => 'required|array|min:1',
'tables.*' => 'exists:tables,id',
'cron_expression' => 'required|string|max:100',
'timezone' => 'nullable|string|max:50',
'is_active' => 'boolean',
'run_in_parallel' => 'boolean',
'batch_size' => 'integer|min:1',
'truncate_before_migration' => 'boolean',
'create_indexes_after' => 'boolean',
'python_script_path' => 'nullable|string',
'description' => 'nullable|string',
]);
$validated['timezone'] = $validated['timezone'] ?? 'UTC';
$validated['is_active'] = $validated['is_active'] ?? true;
$validated['is_incremental'] = $validated['is_incremental'] ?? false;
$validated['incremental_column'] = $validated['is_incremental'] ? ($validated['incremental_column'] ?? 'updated_at') : null;
$validated['use_life_table'] = $validated['use_life_table'] ?? false;
if ($validated['use_life_table']) {
$validated['life_table_name'] = $validated['life_table_name'] ?? null;
$validated['life_id_column'] = $validated['life_id_column'] ?? null;
$validated['base_id_column'] = $validated['base_id_column'] ?? null;
$validated['operation_column'] = $validated['operation_column'] ?? 'x_Operation';
$validated['datetime_column'] = $validated['datetime_column'] ?? 'x_DateTime';
}
$validated['run_in_parallel'] = $validated['run_in_parallel'] ?? false;
$validated['batch_size'] = $validated['batch_size'] ?? 1000;
$validated['truncate_before_migration'] = $validated['truncate_before_migration'] ?? false;
$validated['create_indexes_after'] = $validated['create_indexes_after'] ?? true;
$validated['python_script_args'] = [
'incremental' => $validated['is_incremental'],
'incremental_column' => $validated['incremental_column'],
'use_life_table' => $validated['use_life_table'],
'life_table_name' => $validated['life_table_name'],
'life_id_column' => $validated['life_id_column'],
'base_id_column' => $validated['base_id_column'],
'operation_column' => $validated['operation_column'],
'datetime_column' => $validated['datetime_column'],
];
$schedule = MigrationSchedule::create($validated);
// Attach tables to schedule
$schedule->scheduledTables()->sync($validated['tables']);
return redirect()->route('migrations.index')
->with('success', 'Migration schedule created successfully.');
}
public function edit(MigrationSchedule $schedule)
{
$schedule->load('scheduledTables');
$sourceDatabases = SourceDatabase::where('is_active', true)->get();
$targetDatabases = TargetDatabase::where('is_active', true)->get();
$tables = Table::with('sourceDatabase')
->where('source_database_id', $schedule->source_database_id)
->get();
return Inertia::render('Migrations/ScheduleForm', [
'schedule' => $schedule,
'sourceDatabases' => $sourceDatabases,
'targetDatabases' => $targetDatabases,
'tables' => $tables,
]);
}
public function update(Request $request, MigrationSchedule $schedule)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'source_database_id' => 'required|exists:source_databases,id',
'target_database_id' => 'required|exists:target_databases,id',
'tables' => 'required|array|min:1',
'tables.*' => 'exists:tables,id',
'cron_expression' => 'required|string|max:100',
'timezone' => 'nullable|string|max:50',
'is_active' => 'boolean',
'is_incremental' => 'boolean',
'incremental_column' => 'nullable|string|max:100',
'use_life_table' => 'boolean',
'life_table_name' => 'nullable|string|max:255',
'life_id_column' => 'nullable|string|max:100',
'base_id_column' => 'nullable|string|max:100',
'operation_column' => 'nullable|string|max:100',
'datetime_column' => 'nullable|string|max:100',
'run_in_parallel' => 'boolean',
'batch_size' => 'integer|min:1',
'truncate_before_migration' => 'boolean',
'create_indexes_after' => 'boolean',
'python_script_path' => 'nullable|string',
'description' => 'nullable|string',
]);
$validated['is_incremental'] = $validated['is_incremental'] ?? false;
$validated['incremental_column'] = $validated['is_incremental'] ? ($validated['incremental_column'] ?? 'updated_at') : null;
$validated['use_life_table'] = $validated['use_life_table'] ?? false;
if ($validated['use_life_table']) {
$validated['life_table_name'] = $validated['life_table_name'] ?? null;
$validated['life_id_column'] = $validated['life_id_column'] ?? null;
$validated['base_id_column'] = $validated['base_id_column'] ?? null;
$validated['operation_column'] = $validated['operation_column'] ?? 'x_Operation';
$validated['datetime_column'] = $validated['datetime_column'] ?? 'x_DateTime';
}
$validated['python_script_args'] = [
'incremental' => $validated['is_incremental'],
'incremental_column' => $validated['incremental_column'],
'use_life_table' => $validated['use_life_table'],
'life_table_name' => $validated['life_table_name'],
'life_id_column' => $validated['life_id_column'],
'base_id_column' => $validated['base_id_column'],
'operation_column' => $validated['operation_column'],
'datetime_column' => $validated['datetime_column'],
];
$schedule->update($validated);
// Sync tables
$schedule->scheduledTables()->sync($validated['tables']);
return redirect()->route('migrations.index')
->with('success', 'Migration schedule updated successfully.');
}
public function destroy(MigrationSchedule $schedule)
{
$schedule->delete();
return redirect()->route('migrations.index')
->with('success', 'Migration schedule deleted successfully.');
}
public function runNow(MigrationSchedule $schedule)
{
// Check if there's already a running or pending migration for this schedule
$existingRun = MigrationRun::where('schedule_id', $schedule->id)
->whereIn('status', ['pending', 'running'])
->latest()
->first();
if ($existingRun) {
return redirect()->back()
->with('warning', 'Миграция уже выполняется или ожидает в очереди.');
}
$migrationRun = MigrationRun::create([
'schedule_id' => $schedule->id,
'status' => 'pending',
'total_tables' => count($schedule->tables),
]);
RunMigrationJob::dispatch($migrationRun)->onQueue('default');
return redirect()->back()
->with('success', 'Миграция запущена.');
}
public function toggle(MigrationSchedule $schedule)
{
$schedule->update(['is_active' => !$schedule->is_active]);
return redirect()->back()
->with('success', 'Schedule ' . ($schedule->is_active ? 'activated' : 'deactivated') . '.');
}
public function show(MigrationSchedule $schedule)
{
$schedule->load(['sourceDatabase', 'targetDatabase', 'scheduledTables']);
$runs = MigrationRun::where('schedule_id', $schedule->id)
->orderBy('created_at', 'desc')
->limit(50)
->get();
return Inertia::render('Migrations/Show', [
'schedule' => $schedule,
'runs' => $runs,
]);
}
}