2026-04-13 09:24:39 +07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Database\Seeders;
|
|
|
|
|
|
2026-04-18 15:50:39 +07:00
|
|
|
use Illuminate\Support\Facades\Schema;
|
2026-04-13 09:24:39 +07:00
|
|
|
use Illuminate\Database\Seeder;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
|
|
|
|
class InitialDataSeeder extends Seeder
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Run the database seeds.
|
|
|
|
|
*/
|
|
|
|
|
public function run(): void
|
|
|
|
|
{
|
|
|
|
|
$sqlPath = base_path('db/kulakposmysql.sql');
|
|
|
|
|
|
|
|
|
|
if (!File::exists($sqlPath)) {
|
|
|
|
|
$this->command->error("SQL file not found at: {$sqlPath}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->command->info("Starting initial data import from: {$sqlPath}");
|
|
|
|
|
|
|
|
|
|
// Disable foreign key checks for PostgreSQL
|
|
|
|
|
if (DB::getDriverName() === 'pgsql') {
|
|
|
|
|
DB::statement("SET session_replication_role = 'replica';");
|
|
|
|
|
} else {
|
2026-04-18 15:50:39 +07:00
|
|
|
Schema::disableForeignKeyConstraints();
|
2026-04-13 09:24:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$handle = fopen($sqlPath, "r");
|
|
|
|
|
if ($handle) {
|
|
|
|
|
$currentTable = null;
|
|
|
|
|
$insertCount = 0;
|
|
|
|
|
$tableColumnMap = [];
|
|
|
|
|
|
|
|
|
|
while (($line = fgets($handle)) !== false) {
|
|
|
|
|
$line = trim($line);
|
|
|
|
|
|
|
|
|
|
// Detect CREATE TABLE statement to extract column order
|
|
|
|
|
if (preg_match('/^CREATE TABLE `(.+?)`/i', $line, $matches)) {
|
|
|
|
|
$currentTable = $matches[1];
|
|
|
|
|
$tableColumnMap[$currentTable] = [];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we are inside a CREATE TABLE block, look for column definitions
|
|
|
|
|
if ($currentTable && preg_match('/^\s*`(.+?)`/i', $line, $colMatches)) {
|
|
|
|
|
$tableColumnMap[$currentTable][] = $colMatches[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// End of CREATE TABLE block
|
|
|
|
|
if ($currentTable && strpos($line, ') ENGINE') !== false) {
|
|
|
|
|
$currentTable = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Detect INSERT INTO statement
|
|
|
|
|
if (preg_match('/^INSERT INTO `(.+?)` VALUES\s*\((.*)\);$/i', $line, $matches)) {
|
|
|
|
|
$tableName = $matches[1];
|
|
|
|
|
$valuesStr = $matches[2];
|
|
|
|
|
|
|
|
|
|
$values = $this->parseValues($valuesStr);
|
|
|
|
|
$sqlColumns = $tableColumnMap[$tableName] ?? [];
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$data = $this->mapValuesToTable($tableName, $values, $sqlColumns);
|
|
|
|
|
if (!empty($data)) {
|
|
|
|
|
DB::table($tableName)->insert($data);
|
|
|
|
|
$insertCount++;
|
|
|
|
|
|
|
|
|
|
if ($insertCount % 100 === 0) {
|
|
|
|
|
$this->command->info("Imported {$insertCount} records...");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$this->command->error("Error inserting into {$tableName}: " . $e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fclose($handle);
|
|
|
|
|
$this->command->info("Finished! Total records imported: {$insertCount}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Re-enable foreign key checks
|
|
|
|
|
if (DB::getDriverName() === 'pgsql') {
|
|
|
|
|
DB::statement("SET session_replication_role = 'origin';");
|
|
|
|
|
// Update sequences for PostgreSQL
|
|
|
|
|
$this->updatePostgresSequences();
|
|
|
|
|
}
|
2026-04-18 15:50:39 +07:00
|
|
|
Schema::enableForeignKeyConstraints();
|
2026-04-13 09:24:39 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update PostgreSQL sequences so they don't clash with imported IDs.
|
|
|
|
|
*/
|
|
|
|
|
private function updatePostgresSequences()
|
|
|
|
|
{
|
|
|
|
|
$this->command->info("Updating PostgreSQL sequences...");
|
|
|
|
|
$tables = DB::select("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'");
|
|
|
|
|
foreach ($tables as $table) {
|
|
|
|
|
$tableName = $table->table_name;
|
|
|
|
|
try {
|
|
|
|
|
$maxId = DB::table($tableName)->max('id');
|
|
|
|
|
if ($maxId) {
|
|
|
|
|
$seqName = "{$tableName}_id_seq";
|
|
|
|
|
// Check if sequence exists
|
|
|
|
|
$seqExists = DB::select("SELECT 1 FROM pg_class WHERE relname = ?", [$seqName]);
|
|
|
|
|
if ($seqExists) {
|
|
|
|
|
DB::statement("SELECT setval(?, ?, true)", [$seqName, $maxId]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
// Ignore if table doesn't have id column or sequence
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Basic parser for MySQL values string: (val1, val2, ...)
|
|
|
|
|
*/
|
|
|
|
|
private function parseValues($str)
|
|
|
|
|
{
|
|
|
|
|
$values = [];
|
|
|
|
|
$i = 0;
|
|
|
|
|
$len = strlen($str);
|
|
|
|
|
$current = '';
|
|
|
|
|
$inString = false;
|
|
|
|
|
$stringChar = '';
|
|
|
|
|
|
|
|
|
|
while ($i < $len) {
|
|
|
|
|
$char = $str[$i];
|
|
|
|
|
|
|
|
|
|
if ($inString) {
|
|
|
|
|
if ($char === $stringChar && ($i === 0 || $str[$i - 1] !== '\\')) {
|
|
|
|
|
$inString = false;
|
|
|
|
|
$values[] = str_replace(['\\\'', '\\"'], ["'", '"'], $current);
|
|
|
|
|
$current = '';
|
|
|
|
|
} else {
|
|
|
|
|
$current .= $char;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ($char === "'" || $char === '"') {
|
|
|
|
|
$inString = true;
|
|
|
|
|
$stringChar = $char;
|
|
|
|
|
} elseif ($char === ',') {
|
|
|
|
|
$val = trim($current);
|
|
|
|
|
if ($val !== '') {
|
|
|
|
|
$values[] = $this->castValue($val);
|
|
|
|
|
}
|
|
|
|
|
$current = '';
|
|
|
|
|
} else {
|
|
|
|
|
$current .= $char;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Last value
|
|
|
|
|
$val = trim($current);
|
|
|
|
|
if ($val !== '') {
|
|
|
|
|
$values[] = $this->castValue($val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function castValue($val)
|
|
|
|
|
{
|
|
|
|
|
if (strtoupper($val) === 'NULL') return null;
|
|
|
|
|
if (is_numeric($val) && (strpos($val, '0') !== 0 || $val === '0')) {
|
|
|
|
|
return $val + 0; // Convert to int or float
|
|
|
|
|
}
|
|
|
|
|
return trim($val, "'\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Map numerical values to column names based on SQL dump schema and filter by DB schema.
|
|
|
|
|
*/
|
|
|
|
|
private function mapValuesToTable($table, $values, $sqlColumns)
|
|
|
|
|
{
|
|
|
|
|
if (empty($sqlColumns) || count($sqlColumns) !== count($values)) {
|
|
|
|
|
return []; // Can't reliably map
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Combine using SQL column names
|
|
|
|
|
$mapped = array_combine($sqlColumns, $values);
|
|
|
|
|
|
|
|
|
|
// Get actual columns in the database
|
|
|
|
|
static $dbColumnsCache = [];
|
|
|
|
|
if (!isset($dbColumnsCache[$table])) {
|
|
|
|
|
$dbColumnsCache[$table] = DB::getSchemaBuilder()->getColumnListing($table);
|
|
|
|
|
}
|
|
|
|
|
$dbColumns = $dbColumnsCache[$table];
|
|
|
|
|
|
|
|
|
|
// Filter out columns that don't exist in the current DB
|
|
|
|
|
return array_intersect_key($mapped, array_flip($dbColumns));
|
|
|
|
|
}
|
|
|
|
|
}
|