Files
SkinbaseNova/app/Services/CollectionLinkedCollectionsService.php
2026-03-28 19:15:39 +01:00

116 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Collection;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class CollectionLinkedCollectionsService
{
public function linkedCollections(Collection $collection): EloquentCollection
{
return $collection->manualRelatedCollections()
->with(['user:id,username,name', 'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at'])
->get();
}
public function publicLinkedCollections(Collection $collection, int $limit = 6): EloquentCollection
{
return $collection->manualRelatedCollections()
->public()
->with(['user:id,username,name', 'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at'])
->limit(max(1, min($limit, 12)))
->get();
}
public function manageableLinkOptions(Collection $collection, User $actor, int $limit = 24): EloquentCollection
{
$linkedIds = $collection->manualRelatedCollections()->pluck('collections.id')->map(static fn ($id) => (int) $id)->all();
return Collection::query()
->with([
'user:id,username,name',
'members',
'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at',
])
->where('id', '!=', $collection->id)
->whereNotIn('id', $linkedIds)
->orderByDesc('updated_at')
->get()
->filter(fn (Collection $candidate): bool => $candidate->canBeManagedBy($actor))
->take(max(1, min($limit, 48)))
->values();
}
/**
* @param array<int, int|string> $relatedCollectionIds
*/
public function syncLinks(Collection $collection, User $actor, array $relatedCollectionIds): Collection
{
$normalizedIds = collect($relatedCollectionIds)
->map(static fn ($id) => (int) $id)
->filter(static fn (int $id): bool => $id > 0)
->reject(fn (int $id): bool => $id === (int) $collection->id)
->unique()
->values();
$targets = $normalizedIds->isEmpty()
? collect()
: Collection::query()
->with('members')
->whereIn('id', $normalizedIds->all())
->get();
if ($targets->count() !== $normalizedIds->count()) {
throw ValidationException::withMessages([
'related_collection_ids' => 'Choose valid collections to link.',
]);
}
if ($targets->contains(fn (Collection $target): bool => ! $target->canBeManagedBy($actor))) {
throw ValidationException::withMessages([
'related_collection_ids' => 'You can only link collections that you can manage.',
]);
}
$before = $collection->manualRelatedCollections()->pluck('collections.id')->map(static fn ($id) => (int) $id)->all();
DB::transaction(function () use ($collection, $actor, $normalizedIds): void {
DB::table('collection_related_links')
->where('collection_id', $collection->id)
->delete();
if ($normalizedIds->isEmpty()) {
return;
}
$now = now();
DB::table('collection_related_links')->insert($normalizedIds->values()->map(
fn (int $relatedId, int $index): array => [
'collection_id' => $collection->id,
'related_collection_id' => $relatedId,
'sort_order' => $index,
'created_by_user_id' => $actor->id,
'created_at' => $now,
'updated_at' => $now,
]
)->all());
});
$fresh = $collection->fresh(['user.profile', 'coverArtwork']);
app(CollectionHistoryService::class)->record($fresh, $actor, 'linked_collections_updated', 'Manual linked collections updated.', [
'related_collection_ids' => $before,
], [
'related_collection_ids' => $normalizedIds->all(),
]);
return $fresh;
}
}