Overview
The Watchlist model manages user watchlists for both VOD streams and series. It uses a polymorphic relationship to support multiple media types in a single table.
Model Path: app/Models/Watchlist.php
Table: watchlists
Database Schema
Auto-incrementing primary key
Foreign key to users table (cascade on delete)
Polymorphic foreign key to the watchable item (Series or VodStream)
Polymorphic type (e.g., ‘App\Models\Series’ or ‘App\Models\VodStream’)
Record creation timestamp
Record last update timestamp
Fillable Attributes
[
'user_id',
'watchable_id',
'watchable_type',
]
Constraints
Unique Constraint
The table has a unique composite index to prevent duplicate watchlist entries:
['user_id', 'watchable_id', 'watchable_type']
This ensures a user cannot add the same item to their watchlist multiple times.
Foreign Key Constraint
user_id → users.id (cascade on delete)
- When a user is deleted, all their watchlist entries are automatically removed
Relationships
User
Belongs to a User:
public function user(): BelongsTo
Usage:
$watchlistItem = Watchlist::find(1);
$user = $watchlistItem->user;
Watchable (Polymorphic)
Polymorphic relationship to either VodStream or Series:
public function watchable(): MorphTo
Usage:
$watchlistItem = Watchlist::find(1);
$media = $watchlistItem->watchable; // Returns VodStream or Series
if ($media instanceof VodStream) {
// Handle VOD
} elseif ($media instanceof Series) {
// Handle series
}
Common Operations
Add to Watchlist
// Add a VOD stream to watchlist
Watchlist::create([
'user_id' => auth()->id(),
'watchable_id' => $vodStream->stream_id,
'watchable_type' => VodStream::class,
]);
// Add a series to watchlist
Watchlist::create([
'user_id' => auth()->id(),
'watchable_id' => $series->series_id,
'watchable_type' => Series::class,
]);
Using Polymorphic Helper
// Add using relationship
$user->watchlists()->create([
'watchable_id' => $vodStream->stream_id,
'watchable_type' => VodStream::class,
]);
// Or from the media model
$vodStream->watchlists()->create([
'user_id' => auth()->id(),
]);
Get User’s Watchlist
// Get all watchlist items for a user
$watchlist = Watchlist::where('user_id', auth()->id())->get();
// With eager loading
$watchlist = Watchlist::with('watchable')
->where('user_id', auth()->id())
->get();
// Group by type
$vodWatchlist = Watchlist::where('user_id', auth()->id())
->where('watchable_type', VodStream::class)
->get();
$seriesWatchlist = Watchlist::where('user_id', auth()->id())
->where('watchable_type', Series::class)
->get();
Check if Item is in Watchlist
$isInWatchlist = Watchlist::where('user_id', auth()->id())
->where('watchable_id', $vodStream->stream_id)
->where('watchable_type', VodStream::class)
->exists();
Remove from Watchlist
Watchlist::where('user_id', auth()->id())
->where('watchable_id', $vodStream->stream_id)
->where('watchable_type', VodStream::class)
->delete();
Error Handling
Duplicate Entry
Attempting to add a duplicate item will throw a unique constraint violation:
try {
Watchlist::create([
'user_id' => auth()->id(),
'watchable_id' => $vodStream->stream_id,
'watchable_type' => VodStream::class,
]);
} catch (\Illuminate\Database\QueryException $e) {
if ($e->getCode() === '23000') {
// Duplicate entry - item already in watchlist
}
}
Alternatively, use firstOrCreate:
$watchlistItem = Watchlist::firstOrCreate([
'user_id' => auth()->id(),
'watchable_id' => $vodStream->stream_id,
'watchable_type' => VodStream::class,
]);