PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
$userId = (int) $_SESSION['user_id'];
$errors = [];
$successMessage = '';
$satelliteSearchResults = [];
$minorplanetSearchResults = [];
$cometSearchResults = [];
$satelliteSearchQuery = trim($_GET['sat_q'] ?? '');
$minorplanetSearchQuery = trim($_GET['mp_q'] ?? '');
$cometSearchQuery = trim($_GET['com_q'] ?? '');
$pageTitle = 'Favoriten - AstroTools';
$headerIntroPre = 'Merkliste';
$headerIntroTitle = 'Favoriten';
$headerIntroSub = 'Satelliten und Kleinplaneten zentral verwalten.';
$htmxTriggers = [];
function h(?string $value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
function isHtmxRequest(): bool
{
return strtolower((string) ($_SERVER['HTTP_HX_REQUEST'] ?? '')) === 'true';
}
function renderMessages(string $successMessage, array $errors, bool $oob = false): string
{
ob_start();
?>
>
= h($successMessage) ?>
>
Standorte
Es sind noch keine Standorte gespeichert.
| Name |
Breitengrad |
Laengengrad |
Hoehe |
Zeitzone |
Standard |
|
| = h($location['name']) ?> |
= h((string) $location['latitude']) ?> |
= h((string) $location['longitude']) ?> |
= h($location['elevation'] !== null ? (string) $location['elevation'] . ' m' : '-') ?> |
= h($location['timezone']) ?> |
= (int) $location['is_default'] === 1 ? '*' : '-' ?> |
1): ?>
Letzter Standort
|
>
Noch keine Suche gestartet.
Suche nach Namen oder NORAD-ID, um passende Satelliten direkt hier einzublenden.
Suchergebnisse
= count($satelliteSearchResults) ?> Treffer fuer = h($satelliteSearchQuery) ?>
Keine passenden Satelliten gefunden.
Probiere einen Namen wie ISS oder eine NORAD-ID wie 25544.
| Name |
NORAD |
|
| = h($satellite['object_name']) ?> |
= h((string) $satellite['norad_cat_id']) ?> |
|
>
Noch keine Suche gestartet.
Suche nach Nummer oder Bezeichnung, um passende Kleinplaneten direkt hier einzublenden.
Suchergebnisse
= count($minorplanetSearchResults) ?> Treffer fuer = h($minorplanetSearchQuery) ?>
Keine passenden Kleinplaneten gefunden.
Probiere eine Nummer wie 1 oder eine Bezeichnung wie Ceres.
| Bezeichnung |
Nummer |
|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> |
= h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '-') ?> |
|
>
Meine Satelliten
Du hast noch keine Satelliten ausgewaehlt.
| Name |
NORAD |
Favorit |
|
| = h($satellite['object_name']) ?> |
= h((string) $satellite['norad_cat_id']) ?> |
= (int) $satellite['is_favorite'] === 1 ? '*' : '-' ?> |
Favorit bleibt gesetzt
1): ?>
Letzter Satellit
|
>
Meine Kleinplaneten
Du hast noch keine Kleinplaneten ausgewaehlt.
| Bezeichnung |
Nummer |
Favorit |
|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> |
= h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '-') ?> |
= (int) $minorplanet['is_favorite'] === 1 ? '*' : '-' ?> |
Favorit bleibt gesetzt
1): ?>
Letzter Kleinplanet
|
>
Noch keine Suche gestartet.
Suche nach MPC-Bezeichnung oder Kometenname, um passende Kometen direkt hier einzublenden.
Suchergebnisse
= count($cometSearchResults) ?> Treffer fuer = h($cometSearchQuery) ?>
Keine passenden Kometen gefunden.
Probiere eine Bezeichnung wie 67P oder einen Namen wie Halley.
| Bezeichnung |
|
| = h($comet['designation_and_name']) ?> |
|
>
Meine Kometen
Du hast noch keine Kometen ausgewaehlt.
| Bezeichnung |
Typ |
Favorit |
|
| = h($comet['designation_and_name']) ?> |
= h((string) $comet['orbit_type']) ?> |
= (int) $comet['is_favorite'] === 1 ? '*' : '-' ?> |
Favorit bleibt gesetzt
1): ?>
Letzter Komet
|
beginTransaction();
try {
$stmtCurrent = $pdo->prepare("
SELECT `is_favorite`
FROM `{$tableName}`
WHERE `user_id` = :user_id
AND `{$idColumn}` = :entity_id
LIMIT 1
");
$stmtCurrent->execute([
':user_id' => $userId,
':entity_id' => $entityId,
]);
$current = $stmtCurrent->fetchColumn();
if ($current === false) {
$pdo->rollBack();
return false;
}
$newValue = (int) $current === 1 ? 0 : 1;
if ($newValue === 1) {
$stmtReset = $pdo->prepare("
UPDATE `{$tableName}`
SET `is_favorite` = 0
WHERE `user_id` = :user_id
");
$stmtReset->execute([
':user_id' => $userId,
]);
}
$stmtSet = $pdo->prepare("
UPDATE `{$tableName}`
SET `is_favorite` = :is_favorite
WHERE `user_id` = :user_id
AND `{$idColumn}` = :entity_id
");
$stmtSet->execute([
':is_favorite' => $newValue,
':user_id' => $userId,
':entity_id' => $entityId,
]);
if ($newValue === 0) {
$stmtNextFavorite = $pdo->prepare("
SELECT `{$idColumn}`
FROM `{$tableName}`
WHERE `user_id` = :user_id
AND `{$idColumn}` <> :entity_id
ORDER BY `created_at` ASC, `{$idColumn}` ASC
LIMIT 1
");
$stmtNextFavorite->execute([
':user_id' => $userId,
':entity_id' => $entityId,
]);
$nextEntityId = $stmtNextFavorite->fetchColumn();
if ($nextEntityId !== false) {
$stmtPromote = $pdo->prepare("
UPDATE `{$tableName}`
SET `is_favorite` = 1
WHERE `user_id` = :user_id
AND `{$idColumn}` = :entity_id
");
$stmtPromote->execute([
':user_id' => $userId,
':entity_id' => (int) $nextEntityId,
]);
}
}
$pdo->commit();
return true;
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
throw $e;
}
}
function countUserRows(PDO $pdo, string $tableName, int $userId): int
{
$stmtCount = $pdo->prepare("
SELECT COUNT(*)
FROM `{$tableName}`
WHERE `user_id` = :user_id
");
$stmtCount->execute([
':user_id' => $userId,
]);
return (int) $stmtCount->fetchColumn();
}
function ensureFavoriteIfNeeded(PDO $pdo, string $tableName, string $idColumn, int $userId): void
{
$stmtFavoriteCount = $pdo->prepare("
SELECT COUNT(*)
FROM `{$tableName}`
WHERE `user_id` = :user_id
AND `is_favorite` = 1
");
$stmtFavoriteCount->execute([
':user_id' => $userId,
]);
$favoriteCount = (int) $stmtFavoriteCount->fetchColumn();
if ($favoriteCount > 0) {
return;
}
$stmtNextFavorite = $pdo->prepare("
SELECT `{$idColumn}`
FROM `{$tableName}`
WHERE `user_id` = :user_id
ORDER BY `created_at` ASC, `{$idColumn}` ASC
LIMIT 1
");
$stmtNextFavorite->execute([
':user_id' => $userId,
]);
$nextEntityId = $stmtNextFavorite->fetchColumn();
if ($nextEntityId === false) {
return;
}
$stmtPromote = $pdo->prepare("
UPDATE `{$tableName}`
SET `is_favorite` = 1
WHERE `user_id` = :user_id
AND `{$idColumn}` = :entity_id
");
$stmtPromote->execute([
':user_id' => $userId,
':entity_id' => (int) $nextEntityId,
]);
}
function validateLocationForm(array $input, array &$errors): array
{
$name = trim((string) ($input['name'] ?? ''));
$latitude = trim((string) ($input['latitude'] ?? ''));
$longitude = trim((string) ($input['longitude'] ?? ''));
$elevation = trim((string) ($input['elevation'] ?? ''));
$timezone = trim((string) ($input['timezone'] ?? 'Europe/Berlin'));
if ($name === '') {
$errors[] = 'Bitte einen Namen für den Standort eingeben.';
}
if ($latitude === '' || !is_numeric($latitude)) {
$errors[] = 'Bitte einen gültigen Breitengrad eingeben.';
} else {
$lat = (float) $latitude;
if ($lat < -90 || $lat > 90) {
$errors[] = 'Der Breitengrad muss zwischen -90 und 90 liegen.';
}
}
if ($longitude === '' || !is_numeric($longitude)) {
$errors[] = 'Bitte einen gültigen Längengrad eingeben.';
} else {
$lon = (float) $longitude;
if ($lon < -180 || $lon > 180) {
$errors[] = 'Der Längengrad muss zwischen -180 und 180 liegen.';
}
}
if ($elevation !== '' && !is_numeric($elevation)) {
$errors[] = 'Die Höhe muss numerisch sein.';
}
if (!validTimezone($timezone)) {
$errors[] = 'Bitte eine gültige IANA-Zeitzone angeben, z. B. Europe/Berlin.';
}
return [
'name' => $name,
'latitude' => $latitude,
'longitude' => $longitude,
'elevation' => $elevation,
'timezone' => $timezone,
];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'add_satellite') {
$satelliteId = (int) ($_POST['satellite_id'] ?? 0);
if ($satelliteId <= 0) {
$errors[] = 'Ungültiger Satellit.';
}
if (empty($errors)) {
$stmtCheck = $pdo->prepare("
SELECT `id`
FROM `sat_satellites`
WHERE `id` = :id
LIMIT 1
");
$stmtCheck->execute([
':id' => $satelliteId,
]);
if (!$stmtCheck->fetch()) {
$errors[] = 'Der Satellit wurde nicht gefunden.';
}
}
if (empty($errors)) {
$stmtInsert = $pdo->prepare("
INSERT INTO `app_user_satellites` (
`user_id`,
`satellite_id`,
`is_favorite`,
`created_at`
) VALUES (
:user_id,
:satellite_id,
0,
NOW()
)
ON DUPLICATE KEY UPDATE
`satellite_id` = VALUES(`satellite_id`)
");
$stmtInsert->execute([
':user_id' => $userId,
':satellite_id' => $satelliteId,
]);
$successMessage = 'Der Satellit wurde hinzugefuegt.';
}
}
if ($action === 'remove_satellite') {
$satelliteId = (int) ($_POST['satellite_id'] ?? 0);
if ($satelliteId <= 0) {
$errors[] = 'Ungültiger Satellit.';
}
if (empty($errors)) {
$stmtSatellite = $pdo->prepare("
SELECT `satellite_id`, `is_favorite`
FROM `app_user_satellites`
WHERE `user_id` = :user_id
AND `satellite_id` = :satellite_id
LIMIT 1
");
$stmtSatellite->execute([
':user_id' => $userId,
':satellite_id' => $satelliteId,
]);
$satelliteRow = $stmtSatellite->fetch();
if (!$satelliteRow) {
$errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.';
}
}
if (empty($errors)) {
$satelliteCount = countUserRows($pdo, 'app_user_satellites', $userId);
if ($satelliteCount <= 1) {
$errors[] = 'Der letzte Satellit kann nicht gelöscht werden.';
}
}
if (empty($errors)) {
$pdo->beginTransaction();
try {
$stmtDelete = $pdo->prepare("
DELETE FROM `app_user_satellites`
WHERE `user_id` = :user_id
AND `satellite_id` = :satellite_id
");
$stmtDelete->execute([
':user_id' => $userId,
':satellite_id' => $satelliteId,
]);
if ((int) ($satelliteRow['is_favorite'] ?? 0) === 1) {
$stmtNextFavorite = $pdo->prepare("
SELECT `satellite_id`
FROM `app_user_satellites`
WHERE `user_id` = :user_id
ORDER BY `created_at` ASC, `satellite_id` ASC
LIMIT 1
");
$stmtNextFavorite->execute([
':user_id' => $userId,
]);
$nextSatelliteId = $stmtNextFavorite->fetchColumn();
if ($nextSatelliteId !== false) {
$stmtResetFavorites = $pdo->prepare("
UPDATE `app_user_satellites`
SET `is_favorite` = 0
WHERE `user_id` = :user_id
");
$stmtResetFavorites->execute([
':user_id' => $userId,
]);
$stmtSetFavorite = $pdo->prepare("
UPDATE `app_user_satellites`
SET `is_favorite` = 1
WHERE `user_id` = :user_id
AND `satellite_id` = :satellite_id
");
$stmtSetFavorite->execute([
':user_id' => $userId,
':satellite_id' => (int) $nextSatelliteId,
]);
}
}
$pdo->commit();
$successMessage = 'Der Satellit wurde entfernt.';
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errors[] = 'Der Satellit konnte nicht entfernt werden.';
}
}
}
if ($action === 'toggle_satellite_favorite') {
$satelliteId = (int) ($_POST['satellite_id'] ?? 0);
if ($satelliteId <= 0) {
$errors[] = 'Ungültiger Satellit.';
}
if (empty($errors)) {
$stmtCurrentSatellite = $pdo->prepare("
SELECT `is_favorite`
FROM `app_user_satellites`
WHERE `user_id` = :user_id
AND `satellite_id` = :satellite_id
LIMIT 1
");
$stmtCurrentSatellite->execute([
':user_id' => $userId,
':satellite_id' => $satelliteId,
]);
$currentSatelliteFavorite = $stmtCurrentSatellite->fetchColumn();
if ($currentSatelliteFavorite === false) {
$errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.';
}
}
if (empty($errors)) {
$satelliteCount = countUserRows($pdo, 'app_user_satellites', $userId);
if ($satelliteCount <= 1 && (int) $currentSatelliteFavorite === 1) {
$errors[] = 'Beim letzten Satelliten kann der Favorit nicht entfernt werden.';
}
}
if (empty($errors)) {
if (!setExclusiveFavorite($pdo, 'app_user_satellites', 'satellite_id', $userId, $satelliteId)) {
$errors[] = 'Der Satellit ist nicht in deiner Liste vorhanden.';
} else {
$successMessage = 'Der Satelliten-Favorit wurde aktualisiert.';
}
}
}
if ($action === 'add_minorplanet') {
$minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0);
if ($minorplanetId <= 0) {
$errors[] = 'Ungültiger Kleinplanet.';
}
if (empty($errors)) {
$stmtCheck = $pdo->prepare("
SELECT `id`
FROM `minorplanets_mpc`
WHERE `id` = :id
LIMIT 1
");
$stmtCheck->execute([
':id' => $minorplanetId,
]);
if (!$stmtCheck->fetch()) {
$errors[] = 'Der Kleinplanet wurde nicht gefunden.';
}
}
if (empty($errors)) {
$stmtInsert = $pdo->prepare("
INSERT INTO `app_user_minorplanets` (
`user_id`,
`minorplanet_id`,
`is_favorite`,
`created_at`
) VALUES (
:user_id,
:minorplanet_id,
0,
NOW()
)
ON DUPLICATE KEY UPDATE
`minorplanet_id` = VALUES(`minorplanet_id`)
");
$stmtInsert->execute([
':user_id' => $userId,
':minorplanet_id' => $minorplanetId,
]);
$successMessage = 'Der Kleinplanet wurde hinzugefuegt.';
}
}
if ($action === 'remove_minorplanet') {
$minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0);
if ($minorplanetId <= 0) {
$errors[] = 'Ungültiger Kleinplanet.';
}
if (empty($errors)) {
$minorplanetCount = countUserRows($pdo, 'app_user_minorplanets', $userId);
if ($minorplanetCount <= 1) {
$errors[] = 'Der letzte Kleinplanet kann nicht gelöscht werden.';
}
}
if (empty($errors)) {
$stmtDelete = $pdo->prepare("
DELETE FROM `app_user_minorplanets`
WHERE `user_id` = :user_id
AND `minorplanet_id` = :minorplanet_id
");
$stmtDelete->execute([
':user_id' => $userId,
':minorplanet_id' => $minorplanetId,
]);
$successMessage = 'Der Kleinplanet wurde entfernt.';
}
}
if ($action === 'toggle_minorplanet_favorite') {
$minorplanetId = (int) ($_POST['minorplanet_id'] ?? 0);
if ($minorplanetId <= 0) {
$errors[] = 'Ungültiger Kleinplanet.';
}
if (empty($errors)) {
$stmtCurrentMinorplanet = $pdo->prepare("
SELECT `is_favorite`
FROM `app_user_minorplanets`
WHERE `user_id` = :user_id
AND `minorplanet_id` = :minorplanet_id
LIMIT 1
");
$stmtCurrentMinorplanet->execute([
':user_id' => $userId,
':minorplanet_id' => $minorplanetId,
]);
$currentMinorplanetFavorite = $stmtCurrentMinorplanet->fetchColumn();
if ($currentMinorplanetFavorite === false) {
$errors[] = 'Der Kleinplanet ist nicht in deiner Liste vorhanden.';
}
}
if (empty($errors)) {
$minorplanetCount = countUserRows($pdo, 'app_user_minorplanets', $userId);
if ($minorplanetCount <= 1 && (int) $currentMinorplanetFavorite === 1) {
$errors[] = 'Beim letzten Kleinplaneten kann der Favorit nicht entfernt werden.';
}
}
if (empty($errors)) {
if (!setExclusiveFavorite($pdo, 'app_user_minorplanets', 'minorplanet_id', $userId, $minorplanetId)) {
$errors[] = 'Der Kleinplanet ist nicht in deiner Liste vorhanden.';
} else {
$successMessage = 'Der Kleinplaneten-Favorit wurde aktualisiert.';
}
}
}
if ($action === 'add_comet') {
$cometId = (int) ($_POST['comet_id'] ?? 0);
if ($cometId <= 0) {
$errors[] = 'Ungueltiger Komet.';
}
if (empty($errors)) {
$stmtCheck = $pdo->prepare("
SELECT `id`
FROM `comets_mpc`
WHERE `id` = :id
LIMIT 1
");
$stmtCheck->execute([
':id' => $cometId,
]);
if (!$stmtCheck->fetch()) {
$errors[] = 'Der Komet wurde nicht gefunden.';
}
}
if (empty($errors)) {
$stmtInsert = $pdo->prepare("
INSERT INTO `app_user_comets` (
`user_id`,
`comet_id`,
`is_favorite`,
`created_at`
) VALUES (
:user_id,
:comet_id,
0,
NOW()
)
ON DUPLICATE KEY UPDATE
`comet_id` = VALUES(`comet_id`)
");
$stmtInsert->execute([
':user_id' => $userId,
':comet_id' => $cometId,
]);
$successMessage = 'Der Komet wurde hinzugefuegt.';
}
}
if ($action === 'remove_comet') {
$cometId = (int) ($_POST['comet_id'] ?? 0);
if ($cometId <= 0) {
$errors[] = 'Ungueltiger Komet.';
}
if (empty($errors)) {
$cometCount = countUserRows($pdo, 'app_user_comets', $userId);
if ($cometCount <= 1) {
$errors[] = 'Der letzte Komet kann nicht gelöscht werden.';
}
}
if (empty($errors)) {
$stmtDelete = $pdo->prepare("
DELETE FROM `app_user_comets`
WHERE `user_id` = :user_id
AND `comet_id` = :comet_id
");
$stmtDelete->execute([
':user_id' => $userId,
':comet_id' => $cometId,
]);
$successMessage = 'Der Komet wurde entfernt.';
}
}
if ($action === 'toggle_comet_favorite') {
$cometId = (int) ($_POST['comet_id'] ?? 0);
if ($cometId <= 0) {
$errors[] = 'Ungueltiger Komet.';
}
if (empty($errors)) {
$stmtCurrentComet = $pdo->prepare("
SELECT `is_favorite`
FROM `app_user_comets`
WHERE `user_id` = :user_id
AND `comet_id` = :comet_id
LIMIT 1
");
$stmtCurrentComet->execute([
':user_id' => $userId,
':comet_id' => $cometId,
]);
$currentCometFavorite = $stmtCurrentComet->fetchColumn();
if ($currentCometFavorite === false) {
$errors[] = 'Der Komet ist nicht in deiner Liste vorhanden.';
}
}
if (empty($errors)) {
$cometCount = countUserRows($pdo, 'app_user_comets', $userId);
if ($cometCount <= 1 && (int) $currentCometFavorite === 1) {
$errors[] = 'Beim letzten Kometen kann der Favorit nicht entfernt werden.';
}
}
if (empty($errors)) {
if (!setExclusiveFavorite($pdo, 'app_user_comets', 'comet_id', $userId, $cometId)) {
$errors[] = 'Der Komet ist nicht in deiner Liste vorhanden.';
} else {
$successMessage = 'Der Kometen-Favorit wurde aktualisiert.';
}
}
}
if ($action === 'add_location') {
$name = trim($_POST['name'] ?? '');
$latitude = trim($_POST['latitude'] ?? '');
$longitude = trim($_POST['longitude'] ?? '');
$elevation = trim($_POST['elevation'] ?? '');
$timezone = trim($_POST['timezone'] ?? 'Europe/Berlin');
$isDefault = isset($_POST['is_default']) ? 1 : 0;
if ($name === '') {
$errors[] = 'Bitte einen Namen für den Standort eingeben.';
}
if ($latitude === '' || !is_numeric($latitude)) {
$errors[] = 'Bitte einen gültigen Breitengrad eingeben.';
} else {
$lat = (float) $latitude;
if ($lat < -90 || $lat > 90) {
$errors[] = 'Der Breitengrad muss zwischen -90 und 90 liegen.';
}
}
if ($longitude === '' || !is_numeric($longitude)) {
$errors[] = 'Bitte einen gültigen Längengrad eingeben.';
} else {
$lon = (float) $longitude;
if ($lon < -180 || $lon > 180) {
$errors[] = 'Der Längengrad muss zwischen -180 und 180 liegen.';
}
}
if ($elevation !== '' && !is_numeric($elevation)) {
$errors[] = 'Die Hoehe muss numerisch sein.';
}
if (!validTimezone($timezone)) {
$errors[] = 'Bitte eine gültige IANA-Zeitzone angeben, z. B. Europe/Berlin.';
}
if (empty($errors)) {
$pdo->beginTransaction();
try {
if ($isDefault === 1) {
$stmtReset = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 0
WHERE `user_id` = :user_id
");
$stmtReset->execute([
':user_id' => $userId,
]);
}
$stmtInsertLocation = $pdo->prepare("
INSERT INTO `app_user_locations` (
`user_id`,
`name`,
`latitude`,
`longitude`,
`elevation`,
`timezone`,
`is_default`,
`created_at`,
`updated_at`
) VALUES (
:user_id,
:name,
:latitude,
:longitude,
:elevation,
:timezone,
:is_default,
NOW(),
NOW()
)
");
$stmtInsertLocation->execute([
':user_id' => $userId,
':name' => $name,
':latitude' => (float) $latitude,
':longitude' => (float) $longitude,
':elevation' => $elevation !== '' ? (float) $elevation : null,
':timezone' => $timezone,
':is_default' => $isDefault,
]);
$pdo->commit();
$successMessage = 'Der Standort wurde gespeichert.';
$_POST = [];
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errors[] = 'Der Standort konnte nicht gespeichert werden.';
}
}
}
if ($action === 'update_location') {
$locationId = (int) ($_POST['location_id'] ?? 0);
$locationForm = validateLocationForm($_POST, $errors);
$setDefault = isset($_POST['is_default']) ? 1 : 0;
if ($locationId <= 0) {
$errors[] = 'Ungültiger Standort.';
}
$existingLocation = null;
if (empty($errors)) {
$stmtLocation = $pdo->prepare("
SELECT `id`, `is_default`
FROM `app_user_locations`
WHERE `id` = :id
AND `user_id` = :user_id
LIMIT 1
");
$stmtLocation->execute([
':id' => $locationId,
':user_id' => $userId,
]);
$existingLocation = $stmtLocation->fetch();
if (!$existingLocation) {
$errors[] = 'Der Standort wurde nicht gefunden.';
}
}
if (empty($errors)) {
$pdo->beginTransaction();
try {
if ($setDefault === 1) {
$stmtReset = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 0
WHERE `user_id` = :user_id
");
$stmtReset->execute([
':user_id' => $userId,
]);
}
$stmtUpdate = $pdo->prepare("
UPDATE `app_user_locations`
SET
`name` = :name,
`latitude` = :latitude,
`longitude` = :longitude,
`elevation` = :elevation,
`timezone` = :timezone,
`is_default` = :is_default,
`updated_at` = NOW()
WHERE `id` = :id
AND `user_id` = :user_id
");
$stmtUpdate->execute([
':id' => $locationId,
':user_id' => $userId,
':name' => $locationForm['name'],
':latitude' => (float) $locationForm['latitude'],
':longitude' => (float) $locationForm['longitude'],
':elevation' => $locationForm['elevation'] !== '' ? (float) $locationForm['elevation'] : null,
':timezone' => $locationForm['timezone'],
':is_default' => $setDefault === 1 ? 1 : (int) ($existingLocation['is_default'] ?? 0),
]);
$pdo->commit();
$successMessage = 'Der Standort wurde aktualisiert.';
$htmxTriggers['favorites:location-updated'] = true;
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errors[] = 'Der Standort konnte nicht aktualisiert werden.';
}
}
}
if ($action === 'set_default_location') {
$locationId = (int) ($_POST['location_id'] ?? 0);
if ($locationId <= 0) {
$errors[] = 'Ungültiger Standort.';
}
if (empty($errors)) {
$stmtCheckLocation = $pdo->prepare("
SELECT `id`
FROM `app_user_locations`
WHERE `id` = :id
AND `user_id` = :user_id
LIMIT 1
");
$stmtCheckLocation->execute([
':id' => $locationId,
':user_id' => $userId,
]);
if (!$stmtCheckLocation->fetch()) {
$errors[] = 'Der Standort wurde nicht gefunden.';
}
}
if (empty($errors)) {
$pdo->beginTransaction();
try {
$stmtReset = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 0
WHERE `user_id` = :user_id
");
$stmtReset->execute([
':user_id' => $userId,
]);
$stmtSet = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 1
WHERE `id` = :id
AND `user_id` = :user_id
");
$stmtSet->execute([
':id' => $locationId,
':user_id' => $userId,
]);
$pdo->commit();
$successMessage = 'Der Standard-Standort wurde gesetzt.';
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errors[] = 'Der Standard-Standort konnte nicht gesetzt werden.';
}
}
}
if ($action === 'delete_location') {
$locationId = (int) ($_POST['location_id'] ?? 0);
if ($locationId <= 0) {
$errors[] = 'Ungültiger Standort.';
}
if (empty($errors)) {
$stmtLocation = $pdo->prepare("
SELECT `id`, `is_default`
FROM `app_user_locations`
WHERE `id` = :id
AND `user_id` = :user_id
LIMIT 1
");
$stmtLocation->execute([
':id' => $locationId,
':user_id' => $userId,
]);
$locationRow = $stmtLocation->fetch();
if (!$locationRow) {
$errors[] = 'Der Standort wurde nicht gefunden.';
}
}
if (empty($errors)) {
$locationCount = countUserRows($pdo, 'app_user_locations', $userId);
if ($locationCount <= 1) {
$errors[] = 'Der letzte Standort kann nicht gelöscht werden.';
}
}
if (empty($errors)) {
$pdo->beginTransaction();
try {
$stmtDelete = $pdo->prepare("
DELETE FROM `app_user_locations`
WHERE `id` = :id
AND `user_id` = :user_id
");
$stmtDelete->execute([
':id' => $locationId,
':user_id' => $userId,
]);
if ((int) ($locationRow['is_default'] ?? 0) === 1) {
$stmtNextDefault = $pdo->prepare("
SELECT `id`
FROM `app_user_locations`
WHERE `user_id` = :user_id
ORDER BY `name` ASC, `id` ASC
LIMIT 1
");
$stmtNextDefault->execute([
':user_id' => $userId,
]);
$nextLocationId = $stmtNextDefault->fetchColumn();
if ($nextLocationId !== false) {
$stmtResetDefaults = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 0
WHERE `user_id` = :user_id
");
$stmtResetDefaults->execute([
':user_id' => $userId,
]);
$stmtSetDefault = $pdo->prepare("
UPDATE `app_user_locations`
SET `is_default` = 1
WHERE `user_id` = :user_id
AND `id` = :id
");
$stmtSetDefault->execute([
':user_id' => $userId,
':id' => (int) $nextLocationId,
]);
}
}
$pdo->commit();
$successMessage = 'Der Standort wurde gelöscht.';
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errors[] = 'Der Standort konnte nicht gelöscht werden.';
}
}
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
ensureFavoriteIfNeeded($pdo, 'app_user_minorplanets', 'minorplanet_id', $userId);
ensureFavoriteIfNeeded($pdo, 'app_user_comets', 'comet_id', $userId);
}
$stmtLocations = $pdo->prepare("
SELECT
`id`,
`name`,
`latitude`,
`longitude`,
`elevation`,
`timezone`,
`is_default`
FROM `app_user_locations`
WHERE `user_id` = :user_id
ORDER BY `is_default` DESC, `name` ASC
");
$stmtLocations->execute([
':user_id' => $userId,
]);
$locations = $stmtLocations->fetchAll();
$defaultLocation = null;
foreach ($locations as $location) {
if ((int) $location['is_default'] === 1) {
$defaultLocation = $location;
break;
}
}
$mapLat = isset($_POST['latitude']) && is_numeric($_POST['latitude'])
? (float) $_POST['latitude']
: ($defaultLocation ? (float) $defaultLocation['latitude'] : 51.1657);
$mapLon = isset($_POST['longitude']) && is_numeric($_POST['longitude'])
? (float) $_POST['longitude']
: ($defaultLocation ? (float) $defaultLocation['longitude'] : 10.4515);
$mapZoom = $defaultLocation ? 10 : 6;
if ($satelliteSearchQuery !== '') {
if (ctype_digit($satelliteSearchQuery)) {
$stmtSatelliteSearch = $pdo->prepare("
SELECT
s.`id`,
s.`norad_cat_id`,
s.`object_name`,
CASE
WHEN aus.`satellite_id` IS NULL THEN 0
ELSE 1
END AS `already_added`
FROM `sat_satellites` s
LEFT JOIN `app_user_satellites` aus
ON aus.`satellite_id` = s.`id`
AND aus.`user_id` = :user_id
WHERE s.`norad_cat_id` = :norad_cat_id
ORDER BY s.`object_name` ASC
LIMIT 50
");
$stmtSatelliteSearch->execute([
':user_id' => $userId,
':norad_cat_id' => (int) $satelliteSearchQuery,
]);
} else {
$stmtSatelliteSearch = $pdo->prepare("
SELECT
s.`id`,
s.`norad_cat_id`,
s.`object_name`,
CASE
WHEN aus.`satellite_id` IS NULL THEN 0
ELSE 1
END AS `already_added`
FROM `sat_satellites` s
LEFT JOIN `app_user_satellites` aus
ON aus.`satellite_id` = s.`id`
AND aus.`user_id` = :user_id
WHERE s.`object_name` LIKE :query
ORDER BY s.`object_name` ASC
LIMIT 50
");
$stmtSatelliteSearch->execute([
':user_id' => $userId,
':query' => '%' . $satelliteSearchQuery . '%',
]);
}
$satelliteSearchResults = $stmtSatelliteSearch->fetchAll();
}
if ($minorplanetSearchQuery !== '') {
if (ctype_digit($minorplanetSearchQuery)) {
$stmtMinorplanetSearch = $pdo->prepare("
SELECT
mp.`id`,
mp.`mp_number`,
mp.`designation_text`,
mp.`desig_packed`,
CASE
WHEN aum.`minorplanet_id` IS NULL THEN 0
ELSE 1
END AS `already_added`
FROM `minorplanets_mpc` mp
LEFT JOIN `app_user_minorplanets` aum
ON aum.`minorplanet_id` = mp.`id`
AND aum.`user_id` = :user_id
WHERE mp.`mp_number` = :mp_number
ORDER BY mp.`mp_number` ASC, mp.`designation_text` ASC
LIMIT 50
");
$stmtMinorplanetSearch->execute([
':user_id' => $userId,
':mp_number' => (int) $minorplanetSearchQuery,
]);
} else {
$stmtMinorplanetSearch = $pdo->prepare("
SELECT
mp.`id`,
mp.`mp_number`,
mp.`designation_text`,
mp.`desig_packed`,
CASE
WHEN aum.`minorplanet_id` IS NULL THEN 0
ELSE 1
END AS `already_added`
FROM `minorplanets_mpc` mp
LEFT JOIN `app_user_minorplanets` aum
ON aum.`minorplanet_id` = mp.`id`
AND aum.`user_id` = :user_id
WHERE mp.`designation_text` LIKE :query
OR mp.`desig_packed` LIKE :query
ORDER BY mp.`mp_number` IS NULL ASC, mp.`mp_number` ASC, mp.`designation_text` ASC
LIMIT 50
");
$stmtMinorplanetSearch->execute([
':user_id' => $userId,
':query' => '%' . $minorplanetSearchQuery . '%',
]);
}
$minorplanetSearchResults = $stmtMinorplanetSearch->fetchAll();
}
if ($cometSearchQuery !== '') {
$stmtCometSearch = $pdo->prepare("
SELECT
c.`id`,
c.`designation_and_name`,
c.`designation_packed`,
c.`orbit_type`,
CASE
WHEN auc.`comet_id` IS NULL THEN 0
ELSE 1
END AS `already_added`
FROM `comets_mpc` c
LEFT JOIN `app_user_comets` auc
ON auc.`comet_id` = c.`id`
AND auc.`user_id` = :user_id
WHERE c.`designation_and_name` LIKE :query
OR c.`designation_packed` LIKE :query
ORDER BY c.`orbit_type` ASC, c.`designation_and_name` ASC
LIMIT 50
");
$stmtCometSearch->execute([
':user_id' => $userId,
':query' => '%' . $cometSearchQuery . '%',
]);
$cometSearchResults = $stmtCometSearch->fetchAll();
}
$stmtTrackedSatellites = $pdo->prepare("
SELECT
s.`id`,
s.`norad_cat_id`,
s.`object_name`,
aus.`is_favorite`,
aus.`created_at`
FROM `app_user_satellites` aus
INNER JOIN `sat_satellites` s
ON s.`id` = aus.`satellite_id`
WHERE aus.`user_id` = :user_id
ORDER BY aus.`is_favorite` DESC, s.`object_name` ASC
");
$stmtTrackedSatellites->execute([
':user_id' => $userId,
]);
$trackedSatellites = $stmtTrackedSatellites->fetchAll();
$stmtTrackedMinorplanets = $pdo->prepare("
SELECT
mp.`id`,
mp.`mp_number`,
mp.`designation_text`,
mp.`desig_packed`,
aum.`is_favorite`,
aum.`created_at`
FROM `app_user_minorplanets` aum
INNER JOIN `minorplanets_mpc` mp
ON mp.`id` = aum.`minorplanet_id`
WHERE aum.`user_id` = :user_id
ORDER BY aum.`is_favorite` DESC, mp.`mp_number` IS NULL ASC, mp.`mp_number` ASC, mp.`designation_text` ASC
");
$stmtTrackedMinorplanets->execute([
':user_id' => $userId,
]);
$trackedMinorplanets = $stmtTrackedMinorplanets->fetchAll();
$stmtTrackedComets = $pdo->prepare("
SELECT
c.`id`,
c.`designation_and_name`,
c.`orbit_type`,
auc.`is_favorite`,
auc.`created_at`
FROM `app_user_comets` auc
INNER JOIN `comets_mpc` c
ON c.`id` = auc.`comet_id`
WHERE auc.`user_id` = :user_id
ORDER BY auc.`is_favorite` DESC, c.`orbit_type` ASC, c.`designation_and_name` ASC
");
$stmtTrackedComets->execute([
':user_id' => $userId,
]);
$trackedComets = $stmtTrackedComets->fetchAll();
if (isHtmxRequest()) {
if ($_SERVER['REQUEST_METHOD'] === 'GET' && array_key_exists('sat_q', $_GET)) {
echo renderSatelliteSearchResults($satelliteSearchQuery, $satelliteSearchResults);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'GET' && array_key_exists('mp_q', $_GET)) {
echo renderMinorplanetSearchResults($minorplanetSearchQuery, $minorplanetSearchResults);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'GET' && array_key_exists('com_q', $_GET)) {
echo renderCometSearchResults($cometSearchQuery, $cometSearchResults);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($htmxTriggers !== []) {
header('HX-Trigger: ' . (string) json_encode($htmxTriggers));
}
echo renderMessages($successMessage, $errors);
echo renderLocationsSection($locations, true);
echo renderSatelliteSearchResults($satelliteSearchQuery, $satelliteSearchResults, true);
echo renderMinorplanetSearchResults($minorplanetSearchQuery, $minorplanetSearchResults, true);
echo renderCometSearchResults($cometSearchQuery, $cometSearchResults, true);
echo renderTrackedSatellitesSection($trackedSatellites, true);
echo renderTrackedMinorplanetsSection($trackedMinorplanets, true);
echo renderTrackedCometsSection($trackedComets, true);
exit;
}
}
$loggedIn = true;
?>
= renderMessages($successMessage, $errors) ?>
Standorte
Es sind noch keine Standorte gespeichert.
| Name |
Breitengrad |
Längengrad |
Hoehe |
Zeitzone |
Standard |
|
| = h($location['name']) ?> |
= h((string) $location['latitude']) ?> |
= h((string) $location['longitude']) ?> |
= h($location['elevation'] !== null ? (string) $location['elevation'] . ' m' : '-') ?> |
= h($location['timezone']) ?> |
= (int) $location['is_default'] === 1 ? '*' : '-' ?> |
1): ?>
Letzter Standort
|
Standort hinzufuegen
Suche einen Ort, nutze den Browser-Standort oder klicke direkt in die Karte.
Satelliten suchen
Suchergebnisse
Keine passenden Satelliten gefunden.
| Name |
NORAD |
|
| = h($satellite['object_name']) ?> |
= h((string) $satellite['norad_cat_id']) ?> |
|
Noch keine Suche gestartet.
Suche nach Namen oder NORAD-ID, um passende Satelliten direkt hier einzublenden.
Kleinplaneten suchen
Suchergebnisse
Keine passenden Kleinplaneten gefunden.
| Bezeichnung |
Nummer |
|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> |
= h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '—') ?> |
|
Noch keine Suche gestartet.
Suche nach Nummer oder Bezeichnung, um passende Kleinplaneten direkt hier einzublenden.
Kometen suchen
= renderCometSearchResults($cometSearchQuery, $cometSearchResults) ?>
Meine Satelliten
Du hast noch keine Satelliten ausgewählt.
| Name |
NORAD |
Favorit |
|
| = h($satellite['object_name']) ?> |
= h((string) $satellite['norad_cat_id']) ?> |
= (int) $satellite['is_favorite'] === 1 ? '*' : '-' ?> |
Favorit bleibt gesetzt
1): ?>
Letzter Satellit
|
Meine Kleinplaneten
Du hast noch keine Kleinplaneten ausgewählt.
| Bezeichnung |
Nummer |
Favorit |
|
| = h($minorplanet['designation_text'] ?: $minorplanet['desig_packed']) ?> |
= h($minorplanet['mp_number'] !== null ? (string) $minorplanet['mp_number'] : '-') ?> |
= (int) $minorplanet['is_favorite'] === 1 ? '*' : '-' ?> |
Favorit bleibt gesetzt
1): ?>
Letzter Kleinplanet
|
= renderTrackedCometsSection($trackedComets) ?>