feat: add many playlist for music
This commit is contained in:
@@ -82,7 +82,7 @@ public function show($id)
|
||||
{
|
||||
$category = MusicCategory::with(['image', 'playlists' => function($q) {
|
||||
$q->with(['image', 'musics' => function($q2) {
|
||||
$q2->where('is_active', true)->with('image')->orderBy('order');
|
||||
$q2->where('music.is_active', true)->with('image')->orderBy('music_playlist.order');
|
||||
}])->where('is_active', true)->orderBy('order');
|
||||
}])->findOrFail($id);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public function getAllMusic()
|
||||
{
|
||||
$userId = auth()->id();
|
||||
|
||||
$music = Music::with(['image', 'playlist'])
|
||||
$music = Music::with(['image', 'playlists'])
|
||||
->where('type', 'public')
|
||||
->orWhere(function($query) use ($userId) {
|
||||
$query->where('type', 'private')
|
||||
@@ -33,7 +33,7 @@ public function index()
|
||||
{
|
||||
$userId = auth()->id();
|
||||
|
||||
$music = Music::with(['image', 'playlist'])
|
||||
$music = Music::with(['image', 'playlists'])
|
||||
->where('type', 'public')
|
||||
->orWhere(function($query) use ($userId) {
|
||||
$query->where('type', 'private')
|
||||
@@ -51,19 +51,19 @@ public function index()
|
||||
public function getMusicByPlaylist($playlistId)
|
||||
{
|
||||
$playlist = MusicPlaylist::findOrFail($playlistId);
|
||||
|
||||
$music = Music::where('playlist_id', $playlistId)
|
||||
->where('is_active', true)
|
||||
|
||||
$music = $playlist->musics()
|
||||
->where('music.is_active', true)
|
||||
->with(['image', 'tags'])
|
||||
->orderBy('order')
|
||||
->orderBy('music_playlist.order')
|
||||
->get();
|
||||
|
||||
|
||||
return response()->json([
|
||||
'playlist' => $playlist->load('image'),
|
||||
'musics' => $music
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function addToPlaylist(Request $request, $musicId)
|
||||
{
|
||||
$music = Music::where('id', $musicId)
|
||||
@@ -72,48 +72,57 @@ public function addToPlaylist(Request $request, $musicId)
|
||||
->orWhere('user_id', auth()->id());
|
||||
})
|
||||
->firstOrFail();
|
||||
|
||||
|
||||
$data = $request->validate([
|
||||
'playlist_id' => 'required|exists:music_playlists,id',
|
||||
'order' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
$music->update([
|
||||
'playlist_id' => $data['playlist_id'],
|
||||
'order' => $data['order'] ?? $music->order,
|
||||
|
||||
$order = $data['order'] ?? $this->getNextOrderInPlaylist($data['playlist_id']);
|
||||
|
||||
// Add (or update its order) without removing the music from other playlists.
|
||||
$music->playlists()->syncWithoutDetaching([
|
||||
$data['playlist_id'] => ['order' => $order],
|
||||
]);
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Music added to playlist successfully',
|
||||
'music' => $music->load(['image', 'playlist'])
|
||||
'music' => $music->load(['image', 'playlists'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeFromPlaylist($musicId)
|
||||
|
||||
public function removeFromPlaylist(Request $request, $musicId)
|
||||
{
|
||||
$music = Music::where('id', $musicId)
|
||||
->where('user_id', auth()->id())
|
||||
->firstOrFail();
|
||||
|
||||
$music->update(['playlist_id' => null]);
|
||||
|
||||
|
||||
$data = $request->validate([
|
||||
'playlist_id' => 'required|exists:music_playlists,id',
|
||||
]);
|
||||
|
||||
$music->playlists()->detach($data['playlist_id']);
|
||||
|
||||
return response()->json(['message' => 'Music removed from playlist']);
|
||||
}
|
||||
|
||||
|
||||
public function updateOrder(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'playlist_id' => 'required|exists:music_playlists,id',
|
||||
'musics' => 'required|array',
|
||||
'musics.*.id' => 'required|exists:music,id',
|
||||
'musics.*.order' => 'required|integer',
|
||||
]);
|
||||
|
||||
|
||||
$playlist = MusicPlaylist::findOrFail($data['playlist_id']);
|
||||
|
||||
foreach ($data['musics'] as $item) {
|
||||
Music::where('id', $item['id'])
|
||||
->where('user_id', auth()->id())
|
||||
->update(['order' => $item['order']]);
|
||||
$playlist->musics()->updateExistingPivot($item['id'], [
|
||||
'order' => $item['order'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
return response()->json(['message' => 'Order updated successfully']);
|
||||
}
|
||||
// ✅ Upload music
|
||||
@@ -126,7 +135,9 @@ public function store(Request $request)
|
||||
'file' => 'required|mimes:mp3,wav,ogg,flac|max:20971520',
|
||||
'type' => 'nullable|in:public,private',
|
||||
'image_id' => 'nullable|exists:images,id',
|
||||
'playlist_id' => 'nullable|exists:music_playlists,id',
|
||||
'playlist_id' => 'nullable|exists:music_playlists,id', // single (backward compatible)
|
||||
'playlist_ids' => 'nullable|array', // multiple
|
||||
'playlist_ids.*' => 'integer|exists:music_playlists,id',
|
||||
'duration' => 'nullable|integer|min:1', // validates mm:ss or hh:mm:ss
|
||||
]);
|
||||
|
||||
@@ -161,15 +172,26 @@ public function store(Request $request)
|
||||
'file_path' => $path,
|
||||
'type' => $data['type'] ?? 'private',
|
||||
'image_id' => $data['image_id'] ?? null,
|
||||
'playlist_id' => $data['playlist_id'] ?? null,
|
||||
'duration' => $data['duration'] ?? null, // Store as string
|
||||
'order' => $this->getNextOrderInPlaylist($data['playlist_id'] ?? null),
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
// Merge single + multiple playlist inputs into a unique list.
|
||||
$playlistIds = collect($data['playlist_ids'] ?? [])
|
||||
->push($data['playlist_id'] ?? null)
|
||||
->filter()
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
foreach ($playlistIds as $playlistId) {
|
||||
$music->playlists()->syncWithoutDetaching([
|
||||
$playlistId => ['order' => $this->getNextOrderInPlaylist($playlistId)],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Music uploaded successfully',
|
||||
'music' => $music->load(['image', 'playlist', 'tags']),
|
||||
'music' => $music->load(['image', 'playlists', 'tags']),
|
||||
'url' => asset('storage/' . $path),
|
||||
], 201);
|
||||
|
||||
@@ -192,8 +214,11 @@ private function getNextOrderInPlaylist($playlistId)
|
||||
if (!$playlistId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$maxOrder = Music::where('playlist_id', $playlistId)->max('order');
|
||||
|
||||
$maxOrder = \DB::table('music_playlist')
|
||||
->where('playlist_id', $playlistId)
|
||||
->max('order');
|
||||
|
||||
return ($maxOrder ?? -1) + 1;
|
||||
}
|
||||
|
||||
@@ -209,9 +234,7 @@ public function update(Request $request, $id)
|
||||
'type' => 'nullable|in:public,private',
|
||||
'file' => 'nullable|mimes:mp3,wav,ogg,flac|max:20971520',
|
||||
'image_id' => 'nullable|exists:images,id',
|
||||
'playlist_id' => 'nullable|exists:music_playlists,id',
|
||||
'duration' => 'nullable|integer|min:1',
|
||||
'order' => 'nullable|integer',
|
||||
'is_active' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
@@ -228,7 +251,7 @@ public function update(Request $request, $id)
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Music updated successfully',
|
||||
'music' => $music->load(['image', 'playlist', 'tags']),
|
||||
'music' => $music->load(['image', 'playlists', 'tags']),
|
||||
'url' => asset('storage/' . $music->file_path),
|
||||
]);
|
||||
|
||||
@@ -247,8 +270,8 @@ public function show($id)
|
||||
$userId = auth()->id();
|
||||
|
||||
$music = Music::with([
|
||||
'image',
|
||||
'playlist',
|
||||
'image',
|
||||
'playlists',
|
||||
'tags',
|
||||
'comments' => function($query) {
|
||||
$query->with('user')->latest()->limit(10);
|
||||
|
||||
@@ -73,9 +73,9 @@ public function show($id)
|
||||
'subcategories',
|
||||
'image',
|
||||
'musics' => function($q) {
|
||||
$q->where('is_active', true)
|
||||
$q->where('music.is_active', true)
|
||||
->with(['image', 'tags'])
|
||||
->orderBy('order');
|
||||
->orderBy('music_playlist.order');
|
||||
},
|
||||
'comments' => function($q) { // Add comments relationship
|
||||
$q->with('user')->latest()->limit(10);
|
||||
|
||||
@@ -74,7 +74,7 @@ public function show($id)
|
||||
'image',
|
||||
'playlists' => function($q) {
|
||||
$q->with(['image', 'musics' => function($q2) {
|
||||
$q2->where('is_active', true)->with('image')->orderBy('order');
|
||||
$q2->where('music.is_active', true)->with('image')->orderBy('music_playlist.order');
|
||||
}])->where('is_active', true)->orderBy('order');
|
||||
}
|
||||
])->findOrFail($id);
|
||||
|
||||
@@ -20,12 +20,11 @@ class Music extends Model
|
||||
|
||||
|
||||
protected $fillable = [
|
||||
'user_id', 'title', 'artist', 'file_path', 'type',
|
||||
'playlist_id', 'image_id', 'duration', 'order', 'is_active'
|
||||
'user_id', 'title', 'artist', 'file_path', 'type',
|
||||
'image_id', 'duration', 'is_active'
|
||||
];
|
||||
protected $casts = [
|
||||
'duration' => 'integer',
|
||||
'order' => 'integer',
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
protected $attributes = [
|
||||
@@ -36,9 +35,11 @@ public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
public function playlist(): BelongsTo
|
||||
public function playlists(): BelongsToMany
|
||||
{
|
||||
return $this->belongsTo(MusicPlaylist::class, 'playlist_id');
|
||||
return $this->belongsToMany(MusicPlaylist::class, 'music_playlist', 'music_id', 'playlist_id')
|
||||
->withPivot('order')
|
||||
->withTimestamps();
|
||||
}
|
||||
public function tags(): BelongsToMany
|
||||
{
|
||||
|
||||
@@ -43,9 +43,11 @@ public function subcategories(): BelongsToMany
|
||||
}
|
||||
|
||||
|
||||
public function musics(): HasMany
|
||||
public function musics(): BelongsToMany
|
||||
{
|
||||
return $this->hasMany(Music::class, 'playlist_id');
|
||||
return $this->belongsToMany(Music::class, 'music_playlist', 'playlist_id', 'music_id')
|
||||
->withPivot('order')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function image(): BelongsTo
|
||||
@@ -55,11 +57,11 @@ public function image(): BelongsTo
|
||||
|
||||
public function getActiveMusicsAttribute()
|
||||
{
|
||||
return $this->musics()->where('is_active', true)->orderBy('order')->get();
|
||||
return $this->musics()->where('music.is_active', true)->orderBy('music_playlist.order')->get();
|
||||
}
|
||||
|
||||
|
||||
public function getTotalDurationAttribute()
|
||||
{
|
||||
return $this->musics()->where('is_active', true)->sum('duration');
|
||||
return $this->musics()->where('music.is_active', true)->sum('music.duration');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user