Files
back-meditation/app/Http/Controllers/MusicPlaylistController.php
T

208 lines
7.8 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\MusicPlaylist;
use App\Traits\HandlesImageUpload;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class MusicPlaylistController extends Controller
{
use HandlesImageUpload;
public function index(Request $request, $categoryId = null)
{
$query = MusicPlaylist::with(['categories', 'subcategories', 'image', 'detailImage']);
$categoryId = $categoryId ?? $request->input('category_id');
if ($categoryId) {
$query->whereHas('categories', function ($q) use ($categoryId) {
$q->where('music_categories.id', $categoryId);
});
}
if ($request->filled('subcategory_id')) {
$subcategoryId = $request->input('subcategory_id');
$query->whereHas('subcategories', function ($q) use ($subcategoryId) {
$q->where('music_subcategories.id', $subcategoryId);
});
}
$playlists = $query->where('is_active', true)->orderBy('order')->get();
return response()->json($playlists);
}
public function store(Request $request)
{
$data = $request->validate([
'category_ids' => 'nullable|array',
'category_ids.*' => 'integer|exists:music_categories,id',
'subcategory_ids' => 'nullable|array',
'subcategory_ids.*' => 'integer|exists:music_subcategories,id',
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
// Ensure at least one category or subcategory is provided
if (empty($data['category_ids']) && empty($data['subcategory_ids'])) {
return response()->json([
'message' => 'At least one category or subcategory is required'
], 422);
}
$data['slug'] = $this->uniqueSlug($data['name']);
// An uploaded image file takes precedence over a provided image_id.
$data['image_id'] = $this->uploadedImageId($request) ?? ($data['image_id'] ?? null);
$data['detail_image_id'] = $this->uploadedImageId($request, 'detail_image') ?? ($data['detail_image_id'] ?? null);
$playlist = MusicPlaylist::create($data);
$playlist->categories()->sync($data['category_ids'] ?? []);
$playlist->subcategories()->sync($data['subcategory_ids'] ?? []);
return response()->json([
'message' => 'Playlist created successfully',
'playlist' => $playlist->load(['categories', 'subcategories', 'image', 'detailImage'])
], 201);
}
public function show($id)
{
$playlist = MusicPlaylist::with([
'categories',
'subcategories',
'image',
'detailImage',
'musics' => function($q) {
$q->where('music.is_active', true)
->with(['image', 'tags'])
->orderBy('music_playlist.order');
},
'comments' => function($q) { // Add comments relationship
$q->with('user')->latest()->limit(10);
}
])->findOrFail($id);
$userComment = $playlist->userComment();
$comments = $playlist->comments()
->with('user')
->latest()
->paginate(15);
$playlist->append('duration');
return response()->json(array_merge(
$playlist->toArray(),
[
'statistics' => [
'total_musics' => $playlist->musics->count(),
'total_duration' => $playlist->total_duration,
'total_comments' => $playlist->comments_count,
'total_likes' => $playlist->likes_count,
'total_saves' => $playlist->saved_count,
'average_rating' => $playlist->average_rating,
'total_ratings' => $playlist->ratings_count,
'rating_distribution' => $playlist->rating_distribution,
],
'user_interaction' => [
'has_commented' => $playlist->has_user_commented,
'user_comment' => $playlist->user_comment,
'user_comment_id' => $playlist->user_comment_id,
'has_liked' => $playlist->is_liked,
'has_saved' => $playlist->is_saved,
'has_rated' => $playlist->has_user_rated,
'user_rating' => $playlist->user_rating,
],
'comments' => $comments,
]
));
}
public function update(Request $request, $id)
{
$playlist = MusicPlaylist::findOrFail($id);
$data = $request->validate([
'category_ids' => 'sometimes|array',
'category_ids.*' => 'integer|exists:music_categories,id',
'subcategory_ids' => 'sometimes|array',
'subcategory_ids.*' => 'integer|exists:music_subcategories,id',
'name' => 'sometimes|string|max:255',
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
if (isset($data['name'])) {
$data['slug'] = $this->uniqueSlug($data['name'], $playlist->id);
}
// An uploaded image file takes precedence over a provided image_id.
if (($uploadedImageId = $this->uploadedImageId($request)) !== null) {
$data['image_id'] = $uploadedImageId;
}
if (($uploadedDetailImageId = $this->uploadedImageId($request, 'detail_image')) !== null) {
$data['detail_image_id'] = $uploadedDetailImageId;
}
$playlist->update($data);
if (array_key_exists('category_ids', $data)) {
$playlist->categories()->sync($data['category_ids'] ?? []);
}
if (array_key_exists('subcategory_ids', $data)) {
$playlist->subcategories()->sync($data['subcategory_ids'] ?? []);
}
return response()->json([
'message' => 'Playlist updated successfully',
'playlist' => $playlist->load(['categories', 'subcategories', 'image', 'detailImage'])
]);
}
// Build a slug that is unique within music_playlists. Persian names often
// transliterate to the same/empty value, so we fall back and add a counter.
private function uniqueSlug(string $name, ?int $ignoreId = null): string
{
$base = Str::slug($name);
if ($base === '') {
$base = 'playlist';
}
$slug = $base;
$i = 2;
while (
MusicPlaylist::where('slug', $slug)
->when($ignoreId, fn ($q) => $q->where('id', '!=', $ignoreId))
->exists()
) {
$slug = "{$base}-{$i}";
$i++;
}
return $slug;
}
public function destroy($id)
{
$playlist = MusicPlaylist::findOrFail($id);
$playlist->delete();
return response()->json(['message' => 'Playlist deleted successfully']);
}
}