Files
MediaCollectorLibary/app/Models/TvEpisode.php
Lars Behrends ca2d3a6960 ...
2025-10-18 22:03:30 +02:00

179 lines
4.8 KiB
PHP

<?php
namespace App\Models;
class TvEpisode extends Model
{
protected string $table = 'tv_episodes';
protected array $fillable = [
'title',
'overview',
'season_number',
'episode_number',
'air_date',
'runtime_minutes',
'rating',
'imdb_id',
'tmdb_id',
'tvdb_id',
'poster_url',
'backdrop_url',
'is_watched',
'is_favorite',
'metadata',
'tv_show_id',
'source_id'
];
protected array $casts = [
'season_number' => 'int',
'episode_number' => 'int',
'runtime_minutes' => 'int',
'rating' => 'float',
'is_watched' => 'bool',
'is_favorite' => 'bool',
'air_date' => 'date',
'metadata' => 'array'
];
/**
* Get all actors associated with this TV episode
*/
public function actors()
{
$stmt = $this->pdo->prepare("
SELECT a.*
FROM actors a
JOIN actor_tv_episode ate ON a.id = ate.actor_id
WHERE ate.tv_episode_id = :tv_episode_id
ORDER BY a.name ASC
");
$stmt->execute(['tv_episode_id' => $this->id]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* Get the TV show this episode belongs to
*/
public function tvShow()
{
$stmt = $this->pdo->prepare("
SELECT * FROM tv_shows WHERE id = :tv_show_id
");
$stmt->execute(['tv_show_id' => $this->tv_show_id]);
$showData = $stmt->fetch(\PDO::FETCH_ASSOC);
return $showData ? new TvShow($this->pdo, $showData) : null;
}
/**
* Get TV episode statistics
*/
public static function getStats(\PDO $pdo): array
{
$stmt = $pdo->query("
SELECT
COUNT(*) as total_episodes,
COUNT(CASE WHEN is_watched = 1 THEN 1 END) as watched_episodes,
COUNT(CASE WHEN is_favorite = 1 THEN 1 END) as favorite_episodes,
AVG(rating) as avg_rating
FROM tv_episodes
");
return $stmt->fetch(\PDO::FETCH_ASSOC);
}
/**
* Get total count with optional search
*/
public static function getTotalCount(\PDO $pdo, string $search = ''): int
{
$sql = "SELECT COUNT(*) as count FROM tv_episodes te JOIN tv_shows ts ON te.tv_show_id = ts.id JOIN sources s ON te.source_id = s.id";
$params = [];
if (!empty($search)) {
$sql .= " WHERE te.title LIKE :search OR ts.title LIKE :search";
$params['search'] = "%{$search}%";
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
return (int) $stmt->fetch()['count'];
}
/**
* Get all TV episodes with pagination and optional search
*/
public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = ''): array
{
$offset = ($page - 1) * $perPage;
$sql = "
SELECT te.*, ts.title as show_title, s.display_name as source_name
FROM tv_episodes te
JOIN tv_shows ts ON te.tv_show_id = ts.id
JOIN sources s ON te.source_id = s.id
";
$params = [];
if (!empty($search)) {
$sql .= " WHERE te.title LIKE :search OR ts.title LIKE :search";
$params['search'] = "%{$search}%";
}
$sql .= " ORDER BY ts.title ASC, te.season_number ASC, te.episode_number ASC LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, \PDO::PARAM_INT);
foreach ($params as $key => $value) {
$stmt->bindValue(":{$key}", $value);
}
$stmt->execute();
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* Toggle watched status
*/
public function toggleWatched(): bool
{
return $this->update($this->id, [
'is_watched' => !$this->is_watched
]);
}
/**
* Toggle favorite status
*/
public function toggleFavorite(): bool
{
return $this->update($this->id, [
'is_favorite' => !$this->is_favorite
]);
}
/**
* Update rating
*/
public function updateRating(float $rating): bool
{
return $this->update($this->id, [
'rating' => min(10.0, max(0.0, $rating))
]);
}
/**
* Get the source relationship
*/
public function source(): ?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;
}
}