116 lines
4.3 KiB
PHP
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;
|
|
}
|
|
} |