connection = $connection; return $clone; } public function listDatabases(string $sort, string $dir, string $search = ''): array { try { $rows = collect(DB::connection($this->connection)->select(self::QUERY)) ->map(fn ($row) => (array) $row); if ($search !== '') { $needle = mb_strtolower($search); $rows = $rows->filter(function (array $row) use ($needle) { return str_contains(mb_strtolower($row['db_name'] ?? ''), $needle) || str_contains(mb_strtolower($row['state'] ?? ''), $needle); }); } $rows = $rows->sortBy(function (array $row) use ($sort) { if ($sort === 'active_days') { return (int) ($row['active_days'] ?? 0); } return $row[$sort] ?? ''; }, SORT_REGULAR, $dir === 'desc'); $uptime = DB::connection($this->connection)->selectOne( 'SELECT CONVERT(varchar(19), sqlserver_start_time, 120) AS started, DATEDIFF(day, sqlserver_start_time, GETDATE()) AS uptime_days FROM sys.dm_os_sys_info' ); $host = config('database.connections.' . $this->connection . '.host'); return [ 'rows' => $rows->values()->all(), 'meta' => [ 'total' => $rows->count(), 'server' => $host, 'driver' => 'sqlsrv', 'sql_started' => $uptime->started ?? null, 'uptime_days' => $uptime->uptime_days ?? null, ], 'error' => null, ]; } catch (Throwable) { return [ 'rows' => [], 'meta' => [ 'total' => 0, 'server' => config('database.connections.' . $this->connection . '.host'), 'driver' => 'sqlsrv', 'sql_started' => null, 'uptime_days' => null, ], 'error' => 'Unable to load databases. Please check SQL Server connectivity.', ]; } } public function makeOffline(string $databaseName): void { $databaseName = $this->validateName($databaseName); if ($this->isProtected($databaseName)) { throw new InvalidArgumentException('System databases cannot be taken offline.'); } $exists = DB::connection($this->connection)->selectOne( 'SELECT name, state_desc FROM sys.databases WHERE name = ?', [$databaseName] ); if (! $exists) { throw new InvalidArgumentException('Database not found.'); } if (($exists->state_desc ?? '') === 'OFFLINE') { throw new InvalidArgumentException('Database is already offline.'); } $quoted = str_replace(']', ']]', $databaseName); DB::connection($this->connection)->statement( "ALTER DATABASE [{$quoted}] SET OFFLINE WITH ROLLBACK IMMEDIATE" ); } public function isProtected(string $databaseName): bool { return in_array(mb_strtolower($databaseName), self::PROTECTED_DATABASES, true); } public function supportsOffline(): bool { return true; } private function validateName(string $databaseName): string { $databaseName = trim($databaseName); if (! preg_match('/^[a-zA-Z0-9_\-]+$/', $databaseName)) { throw new InvalidArgumentException('Invalid database name.'); } return $databaseName; } }