mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
fix: update multiple songs duplicate values (#1607)
This commit is contained in:
parent
20bded3bca
commit
5441cfb5f3
3 changed files with 59 additions and 11 deletions
|
@ -23,13 +23,24 @@ class SongService
|
||||||
/** @return Collection|array<array-key, Song> */
|
/** @return Collection|array<array-key, Song> */
|
||||||
public function updateSongs(array $ids, SongUpdateData $data): Collection
|
public function updateSongs(array $ids, SongUpdateData $data): Collection
|
||||||
{
|
{
|
||||||
|
if (count($ids) === 1) {
|
||||||
|
// If we're only updating one song, an empty non-required should be converted to the default values.
|
||||||
|
// This allows the user to clear those fields.
|
||||||
|
$data->disc = $data->disc ?: 1;
|
||||||
|
$data->track = $data->track ?: 0;
|
||||||
|
$data->lyrics = $data->lyrics ?: '';
|
||||||
|
$data->year = $data->year ?: null;
|
||||||
|
$data->genre = $data->genre ?: '';
|
||||||
|
$data->albumArtistName = $data->albumArtistName ?: $data->artistName;
|
||||||
|
}
|
||||||
|
|
||||||
return DB::transaction(function () use ($ids, $data): Collection {
|
return DB::transaction(function () use ($ids, $data): Collection {
|
||||||
return collect($ids)->reduce(function (Collection $updated, string $id) use ($data): Collection {
|
return collect($ids)->reduce(function (Collection $updated, string $id) use ($data): Collection {
|
||||||
/** @var Song|null $song */
|
/** @var Song|null $song */
|
||||||
$song = Song::with('album', 'album.artist', 'artist')->find($id);
|
$song = Song::with('album', 'album.artist', 'artist')->find($id);
|
||||||
|
|
||||||
if ($song) {
|
if ($song) {
|
||||||
$updated->push($this->updateSong($song, $data));
|
$updated->push($this->updateSong($song, clone $data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $updated;
|
return $updated;
|
||||||
|
@ -39,15 +50,19 @@ class SongService
|
||||||
|
|
||||||
private function updateSong(Song $song, SongUpdateData $data): Song
|
private function updateSong(Song $song, SongUpdateData $data): Song
|
||||||
{
|
{
|
||||||
|
// for non-nullable fields, if the provided data is empty, use the existing value
|
||||||
$data->albumName = $data->albumName ?: $song->album->name;
|
$data->albumName = $data->albumName ?: $song->album->name;
|
||||||
$data->artistName = $data->artistName ?: $song->artist->name;
|
$data->artistName = $data->artistName ?: $song->artist->name;
|
||||||
$data->albumArtistName = $data->albumArtistName ?: $song->album_artist->name;
|
|
||||||
$data->title = $data->title ?: $song->title;
|
$data->title = $data->title ?: $song->title;
|
||||||
$data->lyrics = $data->lyrics ?: $song->lyrics;
|
|
||||||
$data->track = $data->track ?: $song->track;
|
// For nullable fields, use the existing value only if the provided data is explicitly null.
|
||||||
$data->disc = $data->disc ?: $song->disc;
|
// This allows us to clear those fields.
|
||||||
$data->genre = $data->genre ?: $song->genre;
|
$data->albumArtistName ??= $song->album_artist->name;
|
||||||
$data->year = $data->year ?: $song->year;
|
$data->lyrics ??= $song->lyrics;
|
||||||
|
$data->track ??= $song->track;
|
||||||
|
$data->disc ??= $song->disc;
|
||||||
|
$data->genre ??= $song->genre;
|
||||||
|
$data->year ??= $song->year;
|
||||||
|
|
||||||
$albumArtist = Artist::getOrCreate($data->albumArtistName);
|
$albumArtist = Artist::getOrCreate($data->albumArtistName);
|
||||||
$artist = Artist::getOrCreate($data->artistName);
|
$artist = Artist::getOrCreate($data->artistName);
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class SongUpdateData implements Arrayable
|
||||||
track: (int) $request->input('data.track'),
|
track: (int) $request->input('data.track'),
|
||||||
disc: (int) $request->input('data.disc'),
|
disc: (int) $request->input('data.disc'),
|
||||||
genre: $request->input('data.genre'),
|
genre: $request->input('data.genre'),
|
||||||
year: (int) $request->input('data.year') ?: null,
|
year: (int) $request->input('data.year'),
|
||||||
lyrics: $request->input('data.lyrics'),
|
lyrics: $request->input('data.lyrics'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,15 +93,16 @@ class SongTest extends TestCase
|
||||||
$this->putAs('/api/songs', [
|
$this->putAs('/api/songs', [
|
||||||
'songs' => $songIds,
|
'songs' => $songIds,
|
||||||
'data' => [
|
'data' => [
|
||||||
'title' => 'foo',
|
'title' => null,
|
||||||
'artist_name' => 'John Cena',
|
'artist_name' => 'John Cena',
|
||||||
'album_name' => 'One by One',
|
'album_name' => 'One by One',
|
||||||
'lyrics' => 'bar',
|
'lyrics' => null,
|
||||||
'track' => 9999,
|
'track' => 9999,
|
||||||
],
|
],
|
||||||
], $user)
|
], $user)
|
||||||
->assertOk();
|
->assertOk();
|
||||||
|
|
||||||
|
/** @var Collection|array<array-key, Song> $songs */
|
||||||
$songs = Song::query()->whereIn('id', $songIds)->get();
|
$songs = Song::query()->whereIn('id', $songIds)->get();
|
||||||
|
|
||||||
// All of these songs must now belong to a new album and artist set
|
// All of these songs must now belong to a new album and artist set
|
||||||
|
@ -112,6 +113,13 @@ class SongTest extends TestCase
|
||||||
self::assertSame('John Cena', $songs[0]->artist->name);
|
self::assertSame('John Cena', $songs[0]->artist->name);
|
||||||
self::assertSame($songs[0]->artist_id, $songs[1]->artist_id);
|
self::assertSame($songs[0]->artist_id, $songs[1]->artist_id);
|
||||||
self::assertSame($songs[0]->artist_id, $songs[2]->artist_id);
|
self::assertSame($songs[0]->artist_id, $songs[2]->artist_id);
|
||||||
|
|
||||||
|
self::assertNotSame($songs[0]->title, $songs[1]->title);
|
||||||
|
self::assertNotSame($songs[0]->lyrics, $songs[1]->lyrics);
|
||||||
|
|
||||||
|
self::assertSame(9999, $songs[0]->track);
|
||||||
|
self::assertSame(9999, $songs[1]->track);
|
||||||
|
self::assertSame(9999, $songs[2]->track);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMultipleUpdateCreatingNewAlbumsAndArtists(): void
|
public function testMultipleUpdateCreatingNewAlbumsAndArtists(): void
|
||||||
|
@ -160,7 +168,6 @@ class SongTest extends TestCase
|
||||||
/** @var Song $song */
|
/** @var Song $song */
|
||||||
$song = Song::query()->first();
|
$song = Song::query()->first();
|
||||||
|
|
||||||
|
|
||||||
$this->putAs('/api/songs', [
|
$this->putAs('/api/songs', [
|
||||||
'songs' => [$song->id],
|
'songs' => [$song->id],
|
||||||
'data' => [
|
'data' => [
|
||||||
|
@ -196,6 +203,32 @@ class SongTest extends TestCase
|
||||||
self::assertTrue($album->artist->is($albumArtist));
|
self::assertTrue($album->artist->is($albumArtist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateSingleSongWithEmptyTrackAndDisc(): void
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = User::factory()->admin()->create();
|
||||||
|
|
||||||
|
/** @var Song $song */
|
||||||
|
$song = Song::factory()->create([
|
||||||
|
'track' => 12,
|
||||||
|
'disc' => 2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->putAs('/api/songs', [
|
||||||
|
'songs' => [$song->id],
|
||||||
|
'data' => [
|
||||||
|
'track' => null,
|
||||||
|
'disc' => null,
|
||||||
|
],
|
||||||
|
], $user)
|
||||||
|
->assertOk();
|
||||||
|
|
||||||
|
$song->refresh();
|
||||||
|
|
||||||
|
self::assertSame(0, $song->track);
|
||||||
|
self::assertSame(1, $song->disc);
|
||||||
|
}
|
||||||
|
|
||||||
public function testDeletingByChunk(): void
|
public function testDeletingByChunk(): void
|
||||||
{
|
{
|
||||||
self::assertNotSame(0, Song::query()->count());
|
self::assertNotSame(0, Song::query()->count());
|
||||||
|
|
Loading…
Reference in a new issue