imageHandler = new ImageHandler(); } protected function getType() { return 'Game'; } protected function getTypeSpecificFields() { return []; } protected function validateTypeSpecificFields($data) { // Game spezifische Validierung if (isset($data['hasIcon'])) { $data['hasIcon'] = is_numeric($data['hasIcon']) ? (int)$data['hasIcon'] : 0; } if (isset($data['hasCover'])) { $data['hasCover'] = is_numeric($data['hasCover']) ? (int)$data['hasCover'] : 0; } if (isset($data['hasBackground'])) { $data['hasBackground'] = is_numeric($data['hasBackground']) ? (int)$data['hasBackground'] : 0; } if (isset($data['playtime']) && !is_numeric($data['playtime'])) { $data['playtime'] = is_numeric($data['playtime']) ? (int)$data['playtime'] : 0; } if (isset($data['isInstalled'])) { $data['isInstalled'] = is_numeric($data['isInstalled']) ? (int)$data['isInstalled'] : 0; } if (isset($data['hidden'])) { $data['hidden'] = is_numeric($data['hidden']) ? (int)$data['hidden'] : 0; } if (isset($data['favorite'])) { $data['favorite'] = is_numeric($data['favorite']) ? (int)$data['favorite'] : 0; } return $data; } /** * Process poster field - convert base64 to file path */ protected function processImageField($data, $type) { if ($this->isUpdate && $this->mediaId && isset($data[$type]) && !empty($data[$type])) { $currentMedia = $this->findById($this->mediaId); if ($currentMedia && !empty($currentMedia[$type])) { $oldPoster = $currentMedia[$type]; if (strpos($oldPoster, '/images/') === 0) { $this->imageHandler->deleteImage($oldPoster); } } } if (isset($data[$type]) && !empty($data[$type])) { if (strpos($data[$type], '/images/') === 0 || filter_var($data[$type], FILTER_VALIDATE_URL)) { return $data; } $posterPath = $this->imageHandler->saveBase64Image($data[$type], 'games/'.$type.'/'); if ($posterPath) { $data[$type] = $posterPath; } } return $data; } public function createWithRelations($data) { // Typ setzen $data['type'] = 'Game'; // Typ-spezifische Validierung $data = $this->validateTypeSpecificFields($data); // Poster verarbeiten (Base64 zu Dateipfad) $data = $this->processImageField($data, 'poster'); $data = $this->processImageField($data, 'banner'); $data = $this->processImageField($data, 'icon'); // Basis-Media erstellen $mediaId = parent::createWithRelations($data); // Media-Games Eintrag erstellen $gameData = [ 'media_id' => $mediaId, 'sortingName' => $data['sortingName'] ?? null, 'notes' => $data['notes'] ?? null, 'completionStatus' => $data['completionStatus'] ?? null, 'source' => $data['source'] ?? null, 'gameId' => $data['gameId'] ?? null, 'pluginId' => $data['pluginId'] ?? null, 'isInstalled' => $data['isInstalled'] ?? false, 'installDirectory' => $data['installDirectory'] ?? null, 'installSize' => $data['installSize'] ?? 0, 'hidden' => $data['hidden'] ?? false, 'favorite' => $data['favorite'] ?? false, 'playCount' => $data['playCount'] ?? 0, 'lastActivity' => $data['lastActivity'] ?? null, 'added' => null, 'modified' => null, 'communityScore' => $data['communityScore'] ?? 0, 'criticScore' => $data['criticScore'] ?? 0, 'userScore' => $data['userScore'] ?? 0, 'hasIcon' => $data['hasIcon'] ?? 0, 'hasCover' => $data['hasCover'] ?? 0, 'hasBackground' => $data['hasBackground'] ?? 0, 'version' => $data['version'] ?? null, 'playtime' => $data['playtime'] ?? 0 ]; $mediaGameId = $this->createMediaGame($gameData); // Relationen speichern if (isset($data['achievements']) && is_array($data['achievements'])) { $this->saveAchievements($mediaGameId, $data['achievements']); } if (isset($data['categories']) && is_array($data['categories'])) { $this->saveGameRelation('game_categories', $mediaGameId, $data['categories'], 'category'); } if (isset($data['features']) && is_array($data['features'])) { $this->saveGameRelation('game_features', $mediaGameId, $data['features'], 'feature'); } if (isset($data['platforms']) && is_array($data['platforms'])) { $this->saveGameRelationWithConsole('game_platforms', $mediaGameId, $data['platforms'], 'platform'); } if (isset($data['developers']) && is_array($data['developers'])) { $this->saveGameRelation('game_developers', $mediaGameId, $data['developers'], 'developer'); } if (isset($data['publishers']) && is_array($data['publishers'])) { $this->saveGameRelation('game_publishers', $mediaGameId, $data['publishers'], 'publisher'); } if (isset($data['series']) && is_array($data['series'])) { $this->saveGameRelation('game_series', $mediaGameId, $data['series'], 'series'); } if (isset($data['ageRatings']) && is_array($data['ageRatings'])) { $this->saveGameRelation('game_age_ratings', $mediaGameId, $data['ageRatings'], 'age_rating'); } if (isset($data['regions']) && is_array($data['regions'])) { $this->saveGameRelation('game_regions', $mediaGameId, $data['regions'], 'region'); } if (isset($data['links']) && is_array($data['links'])) { $this->saveLinks($mediaGameId, $data['links']); } return $mediaId; } public function updateWithRelations($id, $data) { // Set update flag and mediaId for image replacement $this->isUpdate = true; $this->mediaId = $id; // Typ-spezifische Validierung $this->validateTypeSpecificFields($data); // Poster verarbeiten (Base64 zu Dateipfad) $data = $this->processImageField($data, 'poster'); $data = $this->processImageField($data, 'banner'); $data = $this->processImageField($data, 'icon'); // Basis-Media aktualisieren parent::updateWithRelations($id, $data); // Media-Games Eintrag aktualisieren $gameData = []; $gameFields = ['sortingName', 'notes', 'completionStatus', 'source', 'gameId', 'pluginId', 'isInstalled', 'installDirectory', 'installSize', 'hidden', 'favorite', 'playCount', 'lastActivity', 'added', 'modified', 'communityScore', 'criticScore', 'userScore', 'hasIcon', 'hasCover', 'hasBackground', 'version', 'playtime']; foreach ($gameFields as $field) { if (array_key_exists($field, $data)) { $gameData[$field] = $data[$field]; } } if (!empty($gameData)) { $this->updateMediaGame($id, $gameData); } // Media-Games ID abrufen $mediaGameId = $this->getMediaGameId($id); if ($mediaGameId) { // Relationen aktualisieren if (isset($data['achievements']) && is_array($data['achievements'])) { $this->pdo->prepare("DELETE FROM achievements WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveAchievements($mediaGameId, $data['achievements']); } if (isset($data['categories']) && is_array($data['categories'])) { $this->pdo->prepare("DELETE FROM game_categories WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_categories', $mediaGameId, $data['categories'], 'category'); } if (isset($data['features']) && is_array($data['features'])) { $this->pdo->prepare("DELETE FROM game_features WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_features', $mediaGameId, $data['features'], 'feature'); } if (isset($data['platforms']) && is_array($data['platforms'])) { $this->pdo->prepare("DELETE FROM game_platforms WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelationWithConsole('game_platforms', $mediaGameId, $data['platforms'], 'platform'); } if (isset($data['developers']) && is_array($data['developers'])) { $this->pdo->prepare("DELETE FROM game_developers WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_developers', $mediaGameId, $data['developers'], 'developer'); } if (isset($data['publishers']) && is_array($data['publishers'])) { $this->pdo->prepare("DELETE FROM game_publishers WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_publishers', $mediaGameId, $data['publishers'], 'publisher'); } if (isset($data['series']) && is_array($data['series'])) { $this->pdo->prepare("DELETE FROM game_series WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_series', $mediaGameId, $data['series'], 'series'); } if (isset($data['ageRatings']) && is_array($data['ageRatings'])) { $this->pdo->prepare("DELETE FROM game_age_ratings WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_age_ratings', $mediaGameId, $data['ageRatings'], 'age_rating'); } if (isset($data['regions']) && is_array($data['regions'])) { $this->pdo->prepare("DELETE FROM game_regions WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveGameRelation('game_regions', $mediaGameId, $data['regions'], 'region'); } if (isset($data['links']) && is_array($data['links'])) { $this->pdo->prepare("DELETE FROM game_links WHERE media_game_id = ?")->execute([$mediaGameId]); $this->saveLinks($mediaGameId, $data['links']); } } return true; } public function getWithGameInfo($id) { $media = parent::getWithRelations($id); if (!$media) { return null; } // Media-Games Daten abrufen $mediaGameId = $this->getMediaGameId($id); if ($mediaGameId) { $gameInfo = $this->getMediaGameData($mediaGameId); $media = array_merge($media, $gameInfo); // Relationen abrufen $media['achievements'] = $this->getAchievements($mediaGameId); $media['categories'] = $this->getGameRelation('game_categories', $mediaGameId, 'category'); $media['features'] = $this->getGameRelation('game_features', $mediaGameId, 'feature'); $media['platforms'] = $this->getGameRelation('game_platforms', $mediaGameId, 'platform'); $media['developers'] = $this->getGameRelation('game_developers', $mediaGameId, 'developer'); $media['publishers'] = $this->getGameRelation('game_publishers', $mediaGameId, 'publisher'); $media['series'] = $this->getGameRelation('game_series', $mediaGameId, 'series'); $media['ageRatings'] = $this->getGameRelation('game_age_ratings', $mediaGameId, 'age_rating'); $media['regions'] = $this->getGameRelation('game_regions', $mediaGameId, 'region'); $media['links'] = $this->getLinks($mediaGameId); } return $media; } public function getGameInfoForList($mediaId) { // Media-Games Daten abrufen (ohne vollständige Relationen für Performance) $mediaGameId = $this->getMediaGameId($mediaId); if (!$mediaGameId) { return null; } $gameInfo = $this->getMediaGameData($mediaGameId); // Nur wichtige Relationen für Listenansicht laden $gameInfo['categories'] = $this->getGameRelation('game_categories', $mediaGameId, 'category'); $gameInfo['platforms'] = $this->getGameRelation('game_platforms', $mediaGameId, 'platform'); $gameInfo['developers'] = $this->getGameRelation('game_developers', $mediaGameId, 'developer'); return $gameInfo; } public static function interpolateQuery($query, $params) { $keys = array(); # build a regular expression for each parameter foreach ($params as $key => $value) { if (is_string($key)) { $keys[] = '/:'.$key.'/'; } else { $keys[] = '/[?]/'; } } $query = preg_replace($keys, $params, $query, 1, $count); #trigger_error('replaced '.$count.' keys'); return $query; } protected function createMediaGame($data) { $stmt = $this->pdo->prepare(" INSERT INTO media_games (media_id, sortingName, notes, completionStatus, source, gameId, pluginId, isInstalled, installDirectory, installSize, hidden, favorite, playCount, lastActivity, added, modified, communityScore, criticScore, userScore, hasIcon, hasCover, hasBackground, version, playtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([ $data['media_id'], $data['sortingName'], $data['notes'], $data['completionStatus'], $data['source'], $data['gameId'], $data['pluginId'], $data['isInstalled'], $data['installDirectory'], $data['installSize'], $data['hidden'], $data['favorite'], $data['playCount'], $data['lastActivity'], $data['added'], $data['modified'], $data['communityScore'], $data['criticScore'], $data['userScore'], $data['hasIcon'], $data['hasCover'], $data['hasBackground'], $data['version'], $data['playtime'] ]); return $this->pdo->lastInsertId(); } protected function updateMediaGame($mediaId, $data) { $setClause = []; $params = []; foreach ($data as $key => $value) { $setClause[] = "$key = ?"; $params[] = $value; } $params[] = $mediaId; $stmt = $this->pdo->prepare(" UPDATE media_games SET " . implode(', ', $setClause) . " WHERE media_id = ? "); $stmt->execute($params); } protected function getMediaGameId($mediaId) { $stmt = $this->pdo->prepare("SELECT id FROM media_games WHERE media_id = ?"); $stmt->execute([$mediaId]); $result = $stmt->fetch(); return $result ? $result['id'] : null; } protected function getMediaGameData($mediaGameId) { $stmt = $this->pdo->prepare("SELECT * FROM media_games WHERE id = ?"); $stmt->execute([$mediaGameId]); $data = $stmt->fetch(); if ($data) { unset($data['id'], $data['media_id']); } return $data ?: []; } protected function saveAchievements($mediaGameId, $achievements) { $stmt = $this->pdo->prepare(" INSERT INTO achievements (media_game_id, name, description, icon, unlocked, unlocked_date) VALUES (?, ?, ?, ?, ?, ?) "); foreach ($achievements as $achievement) { $unlockedDate = null; if (isset($achievement['unlocked']) && $achievement['unlocked'] && isset($achievement['unlocked_date'])) { $unlockedDate = $achievement['unlocked_date']; } $stmt->execute([ $mediaGameId, $achievement['name'] ?? null, $achievement['description'] ?? null, $achievement['icon'] ?? null, $achievement['unlocked'] ?? false, $unlockedDate ]); } } protected function getAchievements($mediaGameId) { $stmt = $this->pdo->prepare("SELECT * FROM achievements WHERE media_game_id = ?"); $stmt->execute([$mediaGameId]); return $stmt->fetchAll(); } protected function saveGameRelation($table, $mediaGameId, $items, $field) { $stmt = $this->pdo->prepare("INSERT INTO $table (media_game_id, $field) VALUES (?, ?)"); foreach ($items as $item) { $stmt->execute([$mediaGameId, $item]); } } protected function consoleExists($name) { $stmt = $this->pdo->prepare("SELECT id FROM media WHERE type = 'Console' AND title = ?"); $stmt->execute([$name]); return $stmt->fetch() !== false; } protected function createConsole($name) { $stmt = $this->pdo->prepare(" INSERT INTO media (title, cleanname, type, createdAt, updatedAt) VALUES (?, ?, 'Console', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) "); $stmt->execute([$name, strtolower(str_replace(' ', '-', $name))]); return $this->pdo->lastInsertId(); } protected function saveGameRelationWithConsole($table, $mediaGameId, $items, $field) { $stmt = $this->pdo->prepare("INSERT INTO $table (media_game_id, $field) VALUES (?, ?)"); foreach ($items as $item) { // Check if console exists, create if not if ($field === 'platform' && !$this->consoleExists($item)) { $this->createConsole($item); } $stmt->execute([$mediaGameId, $item]); } } protected function getGameRelation($table, $mediaGameId, $field) { $stmt = $this->pdo->prepare("SELECT $field FROM $table WHERE media_game_id = ?"); $stmt->execute([$mediaGameId]); $items = $stmt->fetchAll(); return array_map(function($item) use ($field) { return $item[$field]; }, $items); } protected function saveLinks($mediaGameId, $links) { $stmt = $this->pdo->prepare("INSERT INTO game_links (media_game_id, name, url) VALUES (?, ?, ?)"); foreach ($links as $link) { $stmt->execute([ $mediaGameId, $link['name'] ?? null, $link['url'] ?? null ]); } } protected function getLinks($mediaGameId) { $stmt = $this->pdo->prepare("SELECT name, url FROM game_links WHERE media_game_id = ?"); $stmt->execute([$mediaGameId]); return $stmt->fetchAll(); } public function search($filters = [], $page = 1, $limit = 20) { // Nur Games suchen $filters['type'] = 'Game'; return parent::search($filters, $page, $limit); } }