middleware(function ($request, $next) { abort_unless(SystemAccess::canOpenSettings(), 403); return $next($request); }); } public function index() { return view('system_settings.databases.index', [ 'connections' => DatabaseConnection::where('company_id', company_id())->orderBy('id')->get(), ]); } public function create() { return view('system_settings.databases.form', ['connection' => null]); } public function store(Request $request) { $data = $this->validateConnection($request); $data['company_id'] = company_id(); $data['enabled'] = (bool) ($data['enabled'] ?? false); DatabaseConnection::create($data); flash('数据库配置已新增。')->success(); return redirect()->route('system-settings.databases.index'); } public function edit(int $id) { return view('system_settings.databases.form', [ 'connection' => $this->findConnection($id), ]); } public function update(int $id, Request $request) { $connection = $this->findConnection($id); $data = $this->validateConnection($request, $connection); $data['enabled'] = (bool) ($data['enabled'] ?? false); if (empty($data['password'])) { unset($data['password']); } $connection->update($data); flash('数据库配置已修改。')->success(); return redirect()->route('system-settings.databases.index'); } public function destroy(int $id) { $this->findConnection($id)->delete(); flash('数据库配置已删除。')->success(); return redirect()->route('system-settings.databases.index'); } public function export() { $connections = DatabaseConnection::where('company_id', company_id())->orderBy('id')->get(); return response()->streamDownload(function () use ($connections) { $stream = fopen('php://output', 'w'); fwrite($stream, "\xEF\xBB\xBF"); fputcsv($stream, ['name', 'driver', 'host', 'port', 'database_name', 'username', 'password', 'charset', 'enabled']); foreach ($connections as $connection) { fputcsv($stream, [ $connection->name, $connection->driver, $connection->host, $connection->port, $connection->database_name, $connection->username, '', $connection->charset, $connection->enabled ? 1 : 0, ]); } fclose($stream); }, 'database-connections.csv', ['Content-Type' => 'text/csv; charset=UTF-8']); } public function import(Request $request) { $request->validate(['file' => ['required', 'file', 'mimes:csv,txt', 'max:5120']]); $handle = fopen($request->file('file')->getRealPath(), 'r'); $header = fgetcsv($handle); $header = array_map(fn ($value) => trim((string) $value, "\xEF\xBB\xBF \t\n\r\0\x0B"), $header ?: []); $required = ['name', 'driver', 'database_name']; if (array_diff($required, $header)) { fclose($handle); return back()->withErrors(['file' => '文件表头不正确,请先导出模板后填写。']); } $count = 0; DB::transaction(function () use ($handle, $header, &$count) { while (($row = fgetcsv($handle)) !== false) { if (count(array_filter($row, fn ($value) => trim((string) $value) !== '')) === 0) { continue; } $row = array_pad($row, count($header), ''); $data = array_combine($header, array_slice($row, 0, count($header))); $driver = in_array($data['driver'] ?? '', ['mysql', 'pgsql', 'sqlite', 'sqlsrv'], true) ? $data['driver'] : 'mysql'; $attributes = [ 'driver' => $driver, 'host' => $data['host'] ?: null, 'port' => ($data['port'] ?? '') !== '' ? (int) $data['port'] : null, 'database_name' => trim((string) ($data['database_name'] ?? '')), 'username' => $data['username'] ?: null, 'charset' => $data['charset'] ?: 'utf8mb4', 'enabled' => filter_var($data['enabled'] ?? true, FILTER_VALIDATE_BOOL), ]; if (($data['password'] ?? '') !== '') { $attributes['password'] = $data['password']; } if (trim((string) ($data['name'] ?? '')) === '' || $attributes['database_name'] === '') { continue; } DatabaseConnection::updateOrCreate( ['company_id' => company_id(), 'name' => trim($data['name'])], $attributes ); $count++; } }); fclose($handle); flash("已导入 {$count} 条数据库配置。")->success(); return redirect()->route('system-settings.databases.index'); } private function findConnection(int $id): DatabaseConnection { return DatabaseConnection::where('company_id', company_id())->findOrFail($id); } private function validateConnection(Request $request, ?DatabaseConnection $connection = null): array { return $request->validate([ 'name' => [ 'required', 'string', 'max:191', Rule::unique('system_database_connections', 'name') ->where(fn ($query) => $query->where('company_id', company_id())) ->ignore($connection?->id), ], 'driver' => ['required', Rule::in(['mysql', 'pgsql', 'sqlite', 'sqlsrv'])], 'host' => ['nullable', 'string', 'max:191'], 'port' => ['nullable', 'integer', 'between:1,65535'], 'database_name' => ['required', 'string', 'max:191'], 'username' => ['nullable', 'string', 'max:191'], 'password' => ['nullable', 'string', 'max:1000'], 'charset' => ['required', 'string', 'max:30'], 'enabled' => ['nullable', 'boolean'], ]); } }