adasd
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-15 02:41:09 +02:00
parent 0b555e7dd4
commit 7157c98dcb
13 changed files with 614 additions and 20 deletions

View File

@@ -24,11 +24,15 @@ final class KeaHostMetadataRepository
owner TEXT,
location TEXT,
device_type TEXT,
group_name TEXT,
desired_ip TEXT,
notes TEXT,
tags_json JSONB,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)"
);
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
return;
}
@@ -43,11 +47,15 @@ final class KeaHostMetadataRepository
owner TEXT,
location TEXT,
device_type TEXT,
group_name TEXT,
desired_ip TEXT,
notes TEXT,
tags_json TEXT,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)"
);
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
return;
}
@@ -61,11 +69,16 @@ final class KeaHostMetadataRepository
owner TEXT,
location TEXT,
device_type TEXT,
group_name TEXT,
desired_ip TEXT,
notes TEXT,
tags_json TEXT,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
)"
);
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
}
public function findByHostIds(array $hostIds): array
@@ -84,7 +97,7 @@ final class KeaHostMetadataRepository
}
$stmt = $this->pdo->prepare(
'SELECT host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, notes, tags_json, updated_at
'SELECT host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, group_name, desired_ip, notes, tags_json, updated_at
FROM nexus_dhcp_host_meta
WHERE host_id IN (' . implode(', ', $placeholders) . ')'
);
@@ -109,6 +122,8 @@ final class KeaHostMetadataRepository
'owner' => null,
'location' => null,
'device_type' => null,
'group_name' => null,
'desired_ip' => null,
'notes' => null,
'tags' => [],
], $metadata);
@@ -122,9 +137,9 @@ final class KeaHostMetadataRepository
if ($driver === 'pgsql') {
$stmt = $this->pdo->prepare(
"INSERT INTO nexus_dhcp_host_meta (
host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, notes, tags_json, updated_at
host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, group_name, desired_ip, notes, tags_json, updated_at
) VALUES (
:host_id, :hardware_address, :ip_address, :real_name, :device_name, :owner, :location, :device_type, :notes, CAST(:tags_json AS jsonb), NOW()
:host_id, :hardware_address, :ip_address, :real_name, :device_name, :owner, :location, :device_type, :group_name, :desired_ip, :notes, CAST(:tags_json AS jsonb), NOW()
)
ON CONFLICT (host_id) DO UPDATE SET
hardware_address = EXCLUDED.hardware_address,
@@ -134,6 +149,8 @@ final class KeaHostMetadataRepository
owner = EXCLUDED.owner,
location = EXCLUDED.location,
device_type = EXCLUDED.device_type,
group_name = EXCLUDED.group_name,
desired_ip = EXCLUDED.desired_ip,
notes = EXCLUDED.notes,
tags_json = EXCLUDED.tags_json,
updated_at = NOW()"
@@ -141,9 +158,9 @@ final class KeaHostMetadataRepository
} else {
$stmt = $this->pdo->prepare(
"REPLACE INTO nexus_dhcp_host_meta (
host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, notes, tags_json, updated_at
host_id, hardware_address, ip_address, real_name, device_name, owner, location, device_type, group_name, desired_ip, notes, tags_json, updated_at
) VALUES (
:host_id, :hardware_address, :ip_address, :real_name, :device_name, :owner, :location, :device_type, :notes, :tags_json, CURRENT_TIMESTAMP
:host_id, :hardware_address, :ip_address, :real_name, :device_name, :owner, :location, :device_type, :group_name, :desired_ip, :notes, :tags_json, CURRENT_TIMESTAMP
)"
);
}
@@ -157,11 +174,85 @@ final class KeaHostMetadataRepository
'owner' => $this->nullableString($metadata['owner']),
'location' => $this->nullableString($metadata['location']),
'device_type' => $this->nullableString($metadata['device_type']),
'group_name' => $this->nullableString($metadata['group_name']),
'desired_ip' => $this->nullableString($metadata['desired_ip']),
'notes' => $this->nullableString($metadata['notes']),
'tags_json' => $tagsJson,
]);
}
public function listGroups(): array
{
$stmt = $this->pdo->query(
"SELECT DISTINCT group_name
FROM nexus_dhcp_host_meta
WHERE group_name IS NOT NULL AND group_name <> ''
ORDER BY group_name ASC"
);
return array_values(array_filter(array_map(
static fn(array $row): string => (string)($row['group_name'] ?? ''),
$stmt->fetchAll(PDO::FETCH_ASSOC)
)));
}
private function ensureColumn(string $table, string $column, string $definition): void
{
if ($this->columnExists($table, $column)) {
return;
}
$driver = (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$quote = $driver === 'mysql' ? '`' : '"';
try {
$this->pdo->exec(
'ALTER TABLE ' . $quote . $table . $quote
. ' ADD COLUMN ' . $quote . $column . $quote . ' ' . $definition
);
} catch (\PDOException $e) {
if (!$this->columnExists($table, $column)) {
throw $e;
}
}
}
private function columnExists(string $table, string $column): bool
{
$driver = (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver === 'sqlite') {
$stmt = $this->pdo->query('PRAGMA table_info(' . $table . ')');
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
if (($row['name'] ?? '') === $column) {
return true;
}
}
return false;
}
if ($driver === 'pgsql') {
$stmt = $this->pdo->prepare(
"SELECT 1
FROM information_schema.columns
WHERE table_schema = current_schema()
AND table_name = :table
AND column_name = :column
LIMIT 1"
);
} else {
$stmt = $this->pdo->prepare(
"SELECT 1
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = :table
AND column_name = :column
LIMIT 1"
);
}
$stmt->execute(['table' => $table, 'column' => $column]);
return (bool)$stmt->fetchColumn();
}
private function nullableString(mixed $value): ?string
{
$value = trim((string)$value);