'date', 'is_favorite' => 'bool' ]; public function source() { $stmt = $this->pdo->prepare("SELECT * FROM sources WHERE id = :source_id"); $stmt->execute(['source_id' => $this->source_id]); $sourceData = $stmt->fetch(\PDO::FETCH_ASSOC); return $sourceData ? new Source($this->pdo, $sourceData) : null; } /** * Get all albums by this artist */ public function albums() { $stmt = $this->pdo->prepare(" SELECT * FROM music_albums WHERE artist_id = :artist_id ORDER BY release_date DESC, title ASC "); $stmt->execute(['artist_id' => $this->id]); return $stmt->fetchAll(\PDO::FETCH_ASSOC); } /** * Get all tracks by this artist */ public function tracks() { $stmt = $this->pdo->prepare(" SELECT * FROM music_tracks WHERE artist_id = :artist_id ORDER BY album_name ASC, track_number ASC, title ASC "); $stmt->execute(['artist_id' => $this->id]); return $stmt->fetchAll(\PDO::FETCH_ASSOC); } /** * Toggle favorite status */ public function toggleFavorite(): bool { return $this->update($this->id, [ 'is_favorite' => !$this->is_favorite ]); } /** * Get total count of artists with optional filters */ public static function getTotalCount(\PDO $pdo, string $search = '', array $genres = []): int { $where = []; $params = []; $sql = "SELECT COUNT(*) as count FROM music_artists ma JOIN sources s ON ma.source_id = s.id"; if (!empty($search)) { $where[] = "(ma.name LIKE :search OR ma.biography LIKE :search)"; $params[':search'] = "%$search%"; } if (!empty($genres)) { $genreConditions = []; foreach ($genres as $i => $genre) { $param = ":genre_$i"; $genreConditions[] = "ma.genre LIKE $param"; $params[$param] = "%$genre%"; } $where[] = "(" . implode(' OR ', $genreConditions) . ")"; } if (!empty($where)) { $sql .= " WHERE " . implode(' AND ', $where); } $stmt = $pdo->prepare($sql); $stmt->execute($params); return (int)$stmt->fetchColumn(); } /** * Get paginated artists with optional filters */ public static function getAllWithPagination( \PDO $pdo, int $page = 1, int $perPage = 20, string $search = '', array $genres = [], string $sort = 'name_asc' ): array { $offset = ($page - 1) * $perPage; $where = []; $params = []; if (!empty($search)) { $where[] = "(name LIKE :search OR biography LIKE :search)"; $params[':search'] = "%$search%"; } if (!empty($genres)) { $genreConditions = []; foreach ($genres as $i => $genre) { $param = ":genre$i"; $genreConditions[] = "genre LIKE $param"; $params[$param] = "%$genre%"; } $where[] = "(" . implode(' OR ', $genreConditions) . ")"; } // Determine sort order $orderBy = 'name ASC'; switch ($sort) { case 'name_desc': $orderBy = 'name DESC'; break; case 'formed_asc': $orderBy = 'formed_date ASC'; break; case 'formed_desc': $orderBy = 'formed_date DESC'; break; } $sql = "SELECT ma.*, s.display_name as source_name FROM music_artists ma JOIN sources s ON ma.source_id = s.id"; if (!empty($where)) { $sql .= " WHERE " . implode(' AND ', $where); } $sql .= " ORDER BY $orderBy LIMIT :limit OFFSET :offset"; $stmt = $pdo->prepare($sql); // Bind parameters foreach ($params as $key => $value) { $stmt->bindValue($key, $value); } $stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(\PDO::FETCH_ASSOC); } /** * Get all unique genres from artists */ public static function getAvailableGenres(\PDO $pdo): array { $stmt = $pdo->query("SELECT DISTINCT genre FROM music_artists WHERE genre IS NOT NULL AND genre != '' ORDER BY genre"); return $stmt->fetchAll(\PDO::FETCH_COLUMN); } /** * Get artist statistics */ public static function getStats(\PDO $pdo): array { $stmt = $pdo->query(" SELECT COUNT(*) as total_artists, COUNT(CASE WHEN is_favorite = 1 THEN 1 END) as favorite_artists, COUNT(DISTINCT genre) as total_genres FROM music_artists "); return $stmt->fetch(\PDO::FETCH_ASSOC); } }