diff --git a/src/ApiKernel.php b/src/ApiKernel.php index c9caa17..1b91169 100644 --- a/src/ApiKernel.php +++ b/src/ApiKernel.php @@ -1534,6 +1534,79 @@ class ApiKernel return $decoded; } + private function fetchSchemaFromDirect(array $direct, array $tablesAllow = []): array + { + $host = trim((string)($direct['host'] ?? '')); + $dbName = trim((string)($direct['database'] ?? '')); + $user = trim((string)($direct['user'] ?? '')); + $pass = (string)($direct['password'] ?? ''); + $charset = trim((string)($direct['charset'] ?? 'utf8mb4')) ?: 'utf8mb4'; + $port = (int)($direct['port'] ?? 3306); + + if ($host === '' || $dbName === '' || $user === '') { + throw new RuntimeException('DB settings missing'); + } + + $dsn = "mysql:host={$host};port={$port};dbname={$dbName};charset={$charset}"; + $pdo = new PDO($dsn, $user, $pass, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]); + + $whitelist = []; + foreach ($tablesAllow as $tbl) { + if (is_string($tbl) && $tbl !== '') { + $whitelist[strtolower($tbl)] = true; + } + } + + $tablesStmt = $pdo->query('SHOW FULL TABLES'); + $tables = []; + while ($row = $tablesStmt->fetch(PDO::FETCH_NUM)) { + $tableName = $row[0] ?? null; + if (!$tableName) { + continue; + } + if ($whitelist && empty($whitelist[strtolower($tableName)])) { + continue; + } + + $columnsStmt = $pdo->prepare( + 'SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY, EXTRA + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table + ORDER BY ORDINAL_POSITION' + ); + $columnsStmt->execute([ + ':schema' => $dbName, + ':table' => $tableName, + ]); + $columns = []; + foreach ($columnsStmt as $col) { + $columns[] = [ + 'name' => $col['COLUMN_NAME'], + 'type' => $col['DATA_TYPE'], + 'nullable' => ($col['IS_NULLABLE'] === 'YES'), + 'default' => $col['COLUMN_DEFAULT'], + 'key' => $col['COLUMN_KEY'], + 'extra' => $col['EXTRA'], + 'placeholder' => strtoupper($tableName) . '__' . strtoupper($col['COLUMN_NAME']), + ]; + } + + $tables[] = [ + 'name' => $tableName, + 'columns' => $columns, + ]; + } + + return [ + 'ok' => true, + 'tables' => $tables, + 'fetched' => date(DATE_ATOM), + ]; + } + private function placeholderCachePath(string $url, string $token): string { $hash = md5($url . '|' . $token); @@ -2328,7 +2401,8 @@ class ApiKernel { return [ 'tables' => [], - 'mode' => 'direct', + 'mode' => 'bridge', + 'import_type' => 'schema', 'direct' => [ 'host' => '', 'port' => 3306,