findById($id); } public function getWithRelations($id) { $media = $this->findById($id); if (!$media) { return null; } $media['genres'] = $this->getRelatedItems('genres', $id); $media['tags'] = $this->getRelatedItems('tags', $id); $media['studios'] = $this->getRelatedItems('studios', $id); $media['staff'] = $this->getCastForMedia($id); return $media; } public function search($filters = [], $page = 1, $limit = 20) { $conditions = []; if (isset($filters['category'])) { $conditions['category'] = $filters['category']; } if (isset($filters['type'])) { $conditions['type'] = $filters['type']; } if (isset($filters['search'])) { $searchTerm = "%" . $filters['search'] . "%"; $conditions['title'] = [$searchTerm]; // OR Bedingung für description wird separat behandelt } $offset = ($page - 1) * $limit; if (isset($filters['search'])) { // Komplexe Suche mit OR $query = "SELECT * FROM {$this->table} WHERE 1=1"; $params = []; if (isset($filters['category'])) { $query .= " AND category = ?"; $params[] = $filters['category']; } if (isset($filters['type'])) { $query .= " AND type = ?"; $params[] = $filters['type']; } $query .= " AND (title LIKE ? OR description LIKE ?)"; $searchTerm = "%" . $filters['search'] . "%"; $params[] = $searchTerm; $params[] = $searchTerm; $query .= " ORDER BY createdAt DESC LIMIT " . (int)$limit . " OFFSET " . (int)$offset; $stmt = $this->pdo->prepare($query); $stmt->execute($params); $items = $stmt->fetchAll(); // Count Query $countQuery = "SELECT COUNT(*) FROM {$this->table} WHERE 1=1"; $countParams = []; if (isset($filters['category'])) { $countQuery .= " AND category = ?"; $countParams[] = $filters['category']; } if (isset($filters['type'])) { $countQuery .= " AND type = ?"; $countParams[] = $filters['type']; } $countQuery .= " AND (title LIKE ? OR description LIKE ?)"; $countParams[] = $searchTerm; $countParams[] = $searchTerm; $countStmt = $this->pdo->prepare($countQuery); $countStmt->execute($countParams); $total = $countStmt->fetchColumn(); } else { $items = $this->findAll($conditions, 'createdAt DESC', $limit, $offset); $total = $this->count($conditions); } return [ 'items' => $items, 'total' => $total, 'page' => $page, 'limit' => $limit, 'totalPages' => ceil($total / $limit) ]; } public function createWithRelations($data) { $title = $data['title'] ?? null; if (!$title) { throw new Exception('Title is required'); } // cleanname generieren $cleanname = generateCleanName($title); // Basis-Media-Daten extrahieren $mediaData = [ 'title' => $title, 'cleanname' => $cleanname, 'year' => $data['year'] ?? null, 'poster' => $data['poster'] ?? null, 'banner' => $data['banner'] ?? null, 'description' => $data['description'] ?? null, 'rating' => $data['rating'] ?? null, 'category' => $data['category'] ?? null, 'type' => $data['type'] ?? null, 'status' => $data['status'] ?? null, 'aspectRatio' => $data['aspectRatio'] ?? null, 'runtime' => $data['runtime'] ?? null, 'director' => $data['director'] ?? null, 'writer' => $data['writer'] ?? null, 'source' => $data['source'] ?? null, 'releaseDate' => $data['releaseDate'] ?? null ]; $mediaId = $this->create($mediaData); // Relationen speichern if (isset($data['genres']) && is_array($data['genres'])) { $this->saveRelatedItems('genres', $mediaId, $data['genres']); } if (isset($data['tags']) && is_array($data['tags'])) { $this->saveRelatedItems('tags', $mediaId, $data['tags']); } if (isset($data['studios']) && is_array($data['studios'])) { $this->saveRelatedItems('studios', $mediaId, $data['studios']); } if (isset($data['staff']) && is_array($data['staff'])) { $this->saveCastAssignments($mediaId, $data['staff']); } return $mediaId; } public function updateWithRelations($id, $data) { $mediaData = []; foreach (['title', 'year', 'poster', 'banner', 'description', 'rating', 'category', 'type', 'status', 'aspectRatio', 'runtime', 'director', 'writer', 'releaseDate', 'source'] as $field) { if (array_key_exists($field, $data)) { $mediaData[$field] = $data[$field]; } } // Wenn title geändert wurde, cleanname aktualisieren if (isset($data['title'])) { $mediaData['cleanname'] = generateCleanName($data['title']); } if (!empty($mediaData)) { $this->update($id, $mediaData); } // Relationen aktualisieren if (isset($data['genres']) && is_array($data['genres'])) { $this->pdo->prepare("DELETE FROM genres WHERE media_id = ?")->execute([$id]); $this->saveRelatedItems('genres', $id, $data['genres']); } if (isset($data['tags']) && is_array($data['tags'])) { $this->pdo->prepare("DELETE FROM tags WHERE media_id = ?")->execute([$id]); $this->saveRelatedItems('tags', $id, $data['tags']); } if (isset($data['studios']) && is_array($data['studios'])) { $this->pdo->prepare("DELETE FROM studios WHERE media_id = ?")->execute([$id]); $this->saveRelatedItems('studios', $id, $data['studios']); } if (isset($data['staff']) && is_array($data['staff'])) { $this->pdo->prepare("DELETE FROM media_cast WHERE media_id = ?")->execute([$id]); $this->saveCastAssignments($id, $data['staff']); } return true; } public function findByCleanName($cleanname) { $stmt = $this->pdo->prepare("SELECT * FROM {$this->table} WHERE cleanname = ?"); $stmt->execute([$cleanname]); return $stmt->fetch(); } protected function saveRelatedItems($table, $id, $items, $fkColumn = 'media_id') { $valueColumn = $table === 'genres' ? 'genre' : ($table === 'tags' ? 'tag' : ($table === 'occupations' ? 'occupation' : 'studio')); $stmt = $this->pdo->prepare("INSERT INTO $table ($fkColumn, $valueColumn) VALUES (?, ?)"); foreach ($items as $item) { $stmt->execute([$id, $item]); } } protected function getCastForMedia($mediaId) { $stmt = $this->pdo->prepare(" SELECT cs.*, mc.role, mc.characterName, mc.characterImage FROM cast_staff cs INNER JOIN media_cast mc ON cs.id = mc.cast_id WHERE mc.media_id = ? "); $stmt->execute([$mediaId]); $cast = $stmt->fetchAll(); foreach ($cast as &$member) { $member['occupations'] = $this->getRelatedItems('occupations', $member['id'], 'cast_id'); } return $cast; } protected function getRelatedItems($table, $id, $fkColumn = 'media_id') { $stmt = $this->pdo->prepare("SELECT * FROM $table WHERE $fkColumn = ?"); $stmt->execute([$id]); $items = $stmt->fetchAll(); $result = []; foreach ($items as $item) { if ($fkColumn === 'cast_id') { $result[] = $item['occupation']; } else { $result[] = $table === 'genres' ? $item['genre'] : ($table === 'tags' ? $item['tag'] : $item['studio']); } } return $result; } protected function saveCastAssignments($mediaId, $castData) { foreach ($castData as $member) { $castId = null; if (isset($member['id']) && $member['id']) { $castId = $member['id']; } elseif (isset($member['name'])) { $stmt = $this->pdo->prepare("SELECT id FROM cast_staff WHERE name = ? LIMIT 1"); $stmt->execute([$member['name']]); $existing = $stmt->fetch(); if ($existing) { $castId = $existing['id']; } else { $cleanname = generateCleanName($member['name']); $stmt = $this->pdo->prepare(" INSERT INTO cast_staff (name, cleanname, photo, bio, birthDate, birthPlace) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([ $member['name'] ?? null, $cleanname, $member['photo'] ?? null, $member['bio'] ?? null, $member['birthDate'] ?? null, $member['birthPlace'] ?? null ]); $castId = $this->pdo->lastInsertId(); if (isset($member['occupations']) && is_array($member['occupations'])) { $this->saveRelatedItems('occupations', $castId, $member['occupations'], 'cast_id'); } } } if ($castId) { $stmt = $this->pdo->prepare(" INSERT INTO media_cast (media_id, cast_id, role, characterName, characterImage) VALUES (?, ?, ?, ?, ?) "); $stmt->execute([ $mediaId, $castId, $member['role'] ?? null, $member['characterName'] ?? null, $member['characterImage'] ?? null ]); } } } }