Feat/performance relevance (#980)

This commit is contained in:
Kyrch
2025-10-25 01:58:27 -03:00
committed by GitHub
parent 4a7b960d34
commit da93812c12
13 changed files with 78 additions and 173 deletions
@@ -9,6 +9,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Pivots\Wiki\ArtistMember;
use App\Pivots\Wiki\ArtistSong;
use Exception;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Arr;
@@ -137,6 +138,16 @@ class ManageSongPerformances
$soloPerformances->each(fn (Performance $performance) => $performance->forceDelete());
Performance::withoutEvents(function () use ($performancesToCreate) {
foreach ($performancesToCreate as $index => $performanceToSort) {
Performance::query()
->where(Performance::ATTRIBUTE_SONG, $this->song)
->where(Performance::ATTRIBUTE_ARTIST_TYPE, Arr::get($performanceToSort, Performance::ATTRIBUTE_ARTIST_TYPE))
->where(Performance::ATTRIBUTE_ARTIST_ID, Arr::get($performanceToSort, Performance::ATTRIBUTE_ARTIST_ID))
->update([Performance::ATTRIBUTE_RELEVANCE => $index + 1]);
}
});
// Update artist_member table to match memberships
ArtistMember::query()->upsert(
$memberships,
@@ -144,6 +155,8 @@ class ManageSongPerformances
[ArtistMember::ATTRIBUTE_ALIAS, ArtistMember::ATTRIBUTE_AS],
);
$this->syncSongArtist();
DB::commit();
} catch (Exception $e) {
Log::error($e->getMessage());
@@ -155,4 +168,30 @@ class ManageSongPerformances
return $this;
}
/**
* Temporary function where the performances feature synchronizes with the artist_song pivot table.
*/
public function syncSongArtist(): void
{
/** @var Song $song */
$song = Song::query()
->whereKey($this->song)
->first();
$songArtists = [];
foreach ($this->performances as $performance) {
$groupOrArtist = Arr::get($performance, Performance::RELATION_MEMBERSHIP.'.'.Membership::ATTRIBUTE_ARTIST)
?? Arr::get($performance, Performance::ATTRIBUTE_ARTIST_ID);
$songArtists[$groupOrArtist] = [
ArtistSong::ATTRIBUTE_ALIAS => Arr::get($performance, Performance::ATTRIBUTE_ALIAS),
ArtistSong::ATTRIBUTE_AS => Arr::get($performance, Performance::ATTRIBUTE_AS),
];
}
ArtistSong::withoutEvents(function () use ($song, $songArtists) {
$song->artists()->sync($songArtists);
});
}
}
@@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Contracts\Events;
interface SyncArtistSongEvent
{
/**
* Sync the performance with the artist song.
* Temporary function.
*/
public function syncArtistSong(): void;
}
@@ -4,20 +4,14 @@ declare(strict_types=1);
namespace App\Events\Wiki\Song\Performance;
use App\Contracts\Events\SyncArtistSongEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiCreatedEvent;
use App\Models\Wiki\Artist;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Pivots\Wiki\ArtistSong;
use Exception;
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* @extends WikiCreatedEvent<Performance>
*/
class PerformanceCreated extends WikiCreatedEvent implements SyncArtistSongEvent, UpdateRelatedIndicesEvent
class PerformanceCreated extends WikiCreatedEvent implements UpdateRelatedIndicesEvent
{
public function __construct(Performance $performance)
{
@@ -65,28 +59,4 @@ class PerformanceCreated extends WikiCreatedEvent implements SyncArtistSongEvent
$performance->artist->searchable();
}
/**
* Sync the performance with the artist song.
* Temporary function.
*/
public function syncArtistSong(): void
{
$performance = $this->getModel();
$song = $performance->song;
$artist = match (Relation::getMorphedModel($performance->artist_type)) {
Artist::class => $performance->artist,
Membership::class => $performance->artist->group,
default => throw new Exception('Invalid artist type.'),
};
ArtistSong::withoutEvents(function () use ($artist, $song, $performance): void {
$artist->songs()->syncWithPivotValues([$song->getKey()], [
ArtistSong::ATTRIBUTE_ALIAS => $performance->alias,
ArtistSong::ATTRIBUTE_AS => $performance->as,
], false);
});
}
}
@@ -4,23 +4,18 @@ declare(strict_types=1);
namespace App\Events\Wiki\Song\Performance;
use App\Contracts\Events\SyncArtistSongEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiDeletedEvent;
use App\Filament\Resources\Wiki\Song\Performance as PerformanceFilament;
use App\Models\Wiki\Artist;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Pivots\Wiki\ArtistSong;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* @extends WikiDeletedEvent<Performance>
*/
class PerformanceDeleted extends WikiDeletedEvent implements SyncArtistSongEvent, UpdateRelatedIndicesEvent
class PerformanceDeleted extends WikiDeletedEvent implements UpdateRelatedIndicesEvent
{
public function __construct(Performance $performance)
{
@@ -85,38 +80,4 @@ class PerformanceDeleted extends WikiDeletedEvent implements SyncArtistSongEvent
$performance->artist->searchable();
}
/**
* Sync the performance with the artist song.
* Temporary function.
*/
public function syncArtistSong(): void
{
$performance = $this->getModel();
$song = $performance->song;
if (
$performance->artist_type === Relation::getMorphAlias(Membership::class)
&& Performance::query()
->whereBelongsTo($song)
->where(Performance::ATTRIBUTE_ARTIST_TYPE, Relation::getMorphAlias(Membership::class))
->whereHas(Performance::RELATION_ARTIST, fn (Builder $query) => $query->where(Artist::ATTRIBUTE_ID, $performance->artist->group->getKey()))
->exists()
) {
return;
}
$artist = match (Relation::getMorphedModel($performance->artist_type)) {
Artist::class => $performance->artist,
Membership::class => $performance->artist->group,
default => throw new Exception('Invalid artist type.'),
};
ArtistSong::withoutEvents(function () use ($artist, $song): void {
ArtistSong::query()->where([
ArtistSong::ATTRIBUTE_ARTIST => $artist->getKey(),
ArtistSong::ATTRIBUTE_SONG => $song->getKey(),
])->delete();
});
}
}
@@ -4,21 +4,17 @@ declare(strict_types=1);
namespace App\Events\Wiki\Song\Performance;
use App\Contracts\Events\SyncArtistSongEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiRestoredEvent;
use App\Models\Wiki\Artist;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Pivots\Wiki\ArtistSong;
use Exception;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* @extends WikiRestoredEvent<Performance>
*/
class PerformanceRestored extends WikiRestoredEvent implements SyncArtistSongEvent, UpdateRelatedIndicesEvent
class PerformanceRestored extends WikiRestoredEvent implements UpdateRelatedIndicesEvent
{
public function __construct(Performance $performance)
{
@@ -55,27 +51,4 @@ class PerformanceRestored extends WikiRestoredEvent implements SyncArtistSongEve
$performance->artist->searchable();
}
/**
* Sync the performance with the artist song.
* Temporary function.
*/
public function syncArtistSong(): void
{
$performance = $this->getModel();
$song = $performance->song;
$artist = match (Relation::getMorphedModel($performance->artist_type)) {
Artist::class => $performance->artist,
Membership::class => $performance->artist->group,
default => throw new Exception('Invalid artist type.'),
};
ArtistSong::withoutEvents(function () use ($artist, $song, $performance): void {
$artist->songs()->syncWithPivotValues([$song->getKey()], [[
ArtistSong::ATTRIBUTE_ALIAS => $performance->alias,
ArtistSong::ATTRIBUTE_AS => $performance->as,
]], false);
});
}
}
@@ -4,21 +4,17 @@ declare(strict_types=1);
namespace App\Events\Wiki\Song\Performance;
use App\Contracts\Events\SyncArtistSongEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiUpdatedEvent;
use App\Models\Wiki\Artist;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Pivots\Wiki\ArtistSong;
use Exception;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* @extends WikiUpdatedEvent<Performance>
*/
class PerformanceUpdated extends WikiUpdatedEvent implements SyncArtistSongEvent, UpdateRelatedIndicesEvent
class PerformanceUpdated extends WikiUpdatedEvent implements UpdateRelatedIndicesEvent
{
public function __construct(Performance $performance)
{
@@ -56,30 +52,4 @@ class PerformanceUpdated extends WikiUpdatedEvent implements SyncArtistSongEvent
$performance->artist->searchable();
}
/**
* Sync the performance with the artist song.
* Temporary function.
*/
public function syncArtistSong(): void
{
$performance = $this->getModel();
$song = $performance->song;
$artist = match (Relation::getMorphedModel($performance->artist_type)) {
Artist::class => $performance->artist,
Membership::class => $performance->artist->group,
default => throw new Exception('Invalid artist type.'),
};
ArtistSong::withoutEvents(function () use ($artist, $song, $performance): void {
ArtistSong::query()->where([
ArtistSong::ATTRIBUTE_ARTIST => $artist->getKey(),
ArtistSong::ATTRIBUTE_SONG => $song->getKey(),
])->update([
ArtistSong::ATTRIBUTE_ALIAS => $performance->alias,
ArtistSong::ATTRIBUTE_AS => $performance->as,
]);
});
}
}
@@ -62,6 +62,8 @@ class PerformanceForm
->defaultItems(0)
->columns(3)
->columnSpanFull()
->reorderableWithDragAndDrop(false)
->reorderableWithButtons()
->formatStateUsing(function ($livewire, Get $get): array {
/** @var SongModel|null $song */
$song = $livewire instanceof PerformanceSongRelationManager
@@ -93,6 +95,8 @@ class PerformanceForm
->defaultItems(0)
->columns(3)
->columnSpanFull()
->reorderableWithDragAndDrop(false)
->reorderableWithButtons()
->schema([
BelongsTo::make(Membership::ATTRIBUTE_MEMBER)
->resource(ArtistResource::class)
@@ -14,6 +14,7 @@ use App\Models\Wiki\Song\Performance;
use Filament\Actions\Action;
use Filament\Tables\Table;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class PerformanceSongRelationManager extends PerformanceRelationManager
{
@@ -63,7 +64,7 @@ class PerformanceSongRelationManager extends PerformanceRelationManager
$artists = [];
$memberships = [];
foreach ($performances as $performance) {
if ($performance->artist instanceof Membership) {
if ($performance->isMembership()) {
$artists[$performance->artist->artist_id] = [
Performance::ATTRIBUTE_ARTIST_TYPE => $performance->artist_type,
Performance::ATTRIBUTE_ARTIST_ID => $performance->artist->artist_id,
-15
View File
@@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Listeners;
use App\Contracts\Events\SyncArtistSongEvent;
class SyncArtistSong
{
public function handle(SyncArtistSongEvent $event): void
{
$event->syncArtistSong();
}
}
+3 -2
View File
@@ -114,7 +114,7 @@ class Song extends BaseModel implements HasResources, SoftDeletable
return "{$this->animethemes->first()->anime->getName()} {$this->animethemes->first()->slug}";
}
return $this->title_native ?? $this->getKey();
return $this->title_native ?? strval($this->getKey());
}
/**
@@ -142,7 +142,8 @@ class Song extends BaseModel implements HasResources, SoftDeletable
*/
public function performances(): HasMany
{
return $this->hasMany(Performance::class, Performance::ATTRIBUTE_SONG);
return $this->hasMany(Performance::class, Performance::ATTRIBUTE_SONG)
->orderBy(Performance::ATTRIBUTE_RELEVANCE);
}
/**
+3
View File
@@ -28,6 +28,7 @@ use Illuminate\Database\Eloquent\Relations\Relation;
* @property string $artist_type
* @property int $artist_id
* @property Artist|Membership $artist
* @property int|null $relevance
* @property Song $song
*
* @method static PerformanceFactory factory(...$parameters)
@@ -47,6 +48,7 @@ class Performance extends BaseModel implements SoftDeletable
final public const string ATTRIBUTE_ARTIST = 'artist';
final public const string ATTRIBUTE_ALIAS = 'alias';
final public const string ATTRIBUTE_AS = 'as';
final public const string ATTRIBUTE_RELEVANCE = 'relevance';
final public const string RELATION_ARTIST = 'artist';
final public const string RELATION_MEMBERSHIP = self::RELATION_ARTIST;
@@ -63,6 +65,7 @@ class Performance extends BaseModel implements SoftDeletable
Performance::ATTRIBUTE_ARTIST_ID,
Performance::ATTRIBUTE_ALIAS,
Performance::ATTRIBUTE_AS,
Performance::ATTRIBUTE_RELEVANCE,
];
/**
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
use App\Models\Wiki\Song\Performance;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! Schema::hasColumn(Performance::TABLE, Performance::ATTRIBUTE_RELEVANCE)) {
Schema::table(Performance::TABLE, function (Blueprint $table) {
$table->integer(Performance::ATTRIBUTE_RELEVANCE)->nullable()->after(Performance::ATTRIBUTE_AS);
});
}
}
};
-11
View File
@@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
use App\Contracts\Events\SyncArtistSongEvent;
use App\Listeners\SyncArtistSong;
use Illuminate\Support\Facades\Event;
test('listening', function () {
Event::assertListening(SyncArtistSongEvent::class, SyncArtistSong::class);
});