Some checks failed
Tests / PHP 8.1 (push) Has been cancelled
Tests / PHP 8.2 (push) Has been cancelled
Tests / PHP 8.3 (push) Has been cancelled
196 lines
6.7 KiB
PHP
196 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\SystemSettings;
|
|
|
|
use App\Models\Settings\DatabaseConnection;
|
|
use App\Utilities\SystemAccess;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class Databases extends Controller
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->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'],
|
|
]);
|
|
}
|
|
}
|