optimizations
This commit is contained in:
162
app/Services/NovaCards/NovaCardCollectionService.php
Normal file
162
app/Services/NovaCards/NovaCardCollectionService.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\NovaCards;
|
||||
|
||||
use App\Jobs\UpdateNovaCardStatsJob;
|
||||
use App\Models\NovaCard;
|
||||
use App\Models\NovaCardCollection;
|
||||
use App\Models\NovaCardCollectionItem;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class NovaCardCollectionService
|
||||
{
|
||||
public function createCollection(User $user, array $attributes): NovaCardCollection
|
||||
{
|
||||
$name = trim((string) ($attributes['name'] ?? 'Saved Cards'));
|
||||
$slug = $this->uniqueSlug($user, Str::slug($attributes['slug'] ?? $name) ?: 'saved-cards');
|
||||
|
||||
return NovaCardCollection::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'slug' => $slug,
|
||||
'name' => $name,
|
||||
'description' => $attributes['description'] ?? null,
|
||||
'visibility' => $attributes['visibility'] ?? NovaCardCollection::VISIBILITY_PRIVATE,
|
||||
'official' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function createManagedCollection(array $attributes): NovaCardCollection
|
||||
{
|
||||
$owner = User::query()->findOrFail((int) $attributes['user_id']);
|
||||
$name = trim((string) ($attributes['name'] ?? 'Untitled Collection'));
|
||||
$slug = $this->uniqueSlug($owner, Str::slug($attributes['slug'] ?? $name) ?: 'nova-collection');
|
||||
|
||||
return NovaCardCollection::query()->create([
|
||||
'user_id' => $owner->id,
|
||||
'slug' => $slug,
|
||||
'name' => $name,
|
||||
'description' => $attributes['description'] ?? null,
|
||||
'visibility' => $attributes['visibility'] ?? NovaCardCollection::VISIBILITY_PUBLIC,
|
||||
'official' => (bool) ($attributes['official'] ?? false),
|
||||
'featured' => (bool) ($attributes['featured'] ?? false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function listCollections(User $user): array
|
||||
{
|
||||
return NovaCardCollection::query()
|
||||
->withCount('items')
|
||||
->where('user_id', $user->id)
|
||||
->orderByDesc('updated_at')
|
||||
->get()
|
||||
->map(fn (NovaCardCollection $collection): array => [
|
||||
'id' => (int) $collection->id,
|
||||
'slug' => (string) $collection->slug,
|
||||
'name' => (string) $collection->name,
|
||||
'description' => $collection->description,
|
||||
'visibility' => (string) $collection->visibility,
|
||||
'featured' => (bool) $collection->featured,
|
||||
'cards_count' => (int) $collection->cards_count,
|
||||
'items_count' => (int) $collection->items_count,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
public function saveCard(User $user, NovaCard $card, ?int $collectionId = null, ?string $note = null): NovaCardCollection
|
||||
{
|
||||
$collection = $collectionId
|
||||
? NovaCardCollection::query()->where('user_id', $user->id)->findOrFail($collectionId)
|
||||
: $this->defaultCollection($user);
|
||||
|
||||
$this->addCardToCollection($collection, $card, $note);
|
||||
|
||||
return $collection->refresh();
|
||||
}
|
||||
|
||||
public function addCardToCollection(NovaCardCollection $collection, NovaCard $card, ?string $note = null, ?int $sortOrder = null): NovaCardCollectionItem
|
||||
{
|
||||
$sortOrder ??= (int) NovaCardCollectionItem::query()->where('collection_id', $collection->id)->max('sort_order') + 1;
|
||||
|
||||
$item = NovaCardCollectionItem::query()->updateOrCreate([
|
||||
'collection_id' => $collection->id,
|
||||
'card_id' => $card->id,
|
||||
], [
|
||||
'note' => $note,
|
||||
'sort_order' => $sortOrder,
|
||||
]);
|
||||
|
||||
$this->refreshCounts($collection, $card);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function unsaveCard(User $user, NovaCard $card, ?int $collectionId = null): void
|
||||
{
|
||||
$query = NovaCardCollectionItem::query()
|
||||
->where('card_id', $card->id)
|
||||
->whereHas('collection', fn ($builder) => $builder->where('user_id', $user->id));
|
||||
|
||||
if ($collectionId !== null) {
|
||||
$query->where('collection_id', $collectionId);
|
||||
}
|
||||
|
||||
$collectionIds = $query->pluck('collection_id')->unique()->all();
|
||||
$query->delete();
|
||||
|
||||
foreach ($collectionIds as $id) {
|
||||
$collection = NovaCardCollection::query()->find($id);
|
||||
if ($collection) {
|
||||
$this->refreshCounts($collection, $card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeCardFromCollection(NovaCardCollection $collection, NovaCard $card): void
|
||||
{
|
||||
NovaCardCollectionItem::query()
|
||||
->where('collection_id', $collection->id)
|
||||
->where('card_id', $card->id)
|
||||
->delete();
|
||||
|
||||
$this->refreshCounts($collection, $card);
|
||||
}
|
||||
|
||||
public function defaultCollection(User $user): NovaCardCollection
|
||||
{
|
||||
return NovaCardCollection::query()->firstOrCreate([
|
||||
'user_id' => $user->id,
|
||||
'slug' => 'saved-cards',
|
||||
], [
|
||||
'name' => 'Saved Cards',
|
||||
'description' => 'Private library of Nova Cards saved for remixing, referencing, and future collections.',
|
||||
'visibility' => NovaCardCollection::VISIBILITY_PRIVATE,
|
||||
'official' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
private function refreshCounts(NovaCardCollection $collection, NovaCard $card): void
|
||||
{
|
||||
$collection->forceFill([
|
||||
'cards_count' => NovaCardCollectionItem::query()->where('collection_id', $collection->id)->count(),
|
||||
])->save();
|
||||
|
||||
UpdateNovaCardStatsJob::dispatch($card->id);
|
||||
}
|
||||
|
||||
private function uniqueSlug(User $user, string $base): string
|
||||
{
|
||||
$slug = $base;
|
||||
$suffix = 2;
|
||||
|
||||
while (NovaCardCollection::query()->where('user_id', $user->id)->where('slug', $slug)->exists()) {
|
||||
$slug = $base . '-' . $suffix;
|
||||
$suffix++;
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user