Avoid per-comment reaction queries on the deferred comments API by aggregating counts in one service call.
73 lines
2.2 KiB
PHP
73 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Enums\ReactionType;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* Bulk reaction read model for artwork comment trees.
|
|
*
|
|
* The returned value intentionally matches ReactionController's `totals`
|
|
* contract so SSR and API comment payloads can hydrate ReactionBar directly.
|
|
*/
|
|
final class CommentReactionService
|
|
{
|
|
/**
|
|
* @param iterable<int|string> $commentIds
|
|
* @return array<int, array<string, array{emoji:string, label:string, count:int, mine:bool}>>
|
|
*/
|
|
public function forComments(iterable $commentIds, ?int $userId = null): array
|
|
{
|
|
$ids = collect($commentIds)
|
|
->map(static fn ($id): int => (int) $id)
|
|
->filter(static fn (int $id): bool => $id > 0)
|
|
->unique()
|
|
->values()
|
|
->all();
|
|
|
|
if ($ids === []) {
|
|
return [];
|
|
}
|
|
|
|
$counts = DB::table('comment_reactions')
|
|
->whereIn('comment_id', $ids)
|
|
->selectRaw('comment_id, reaction, COUNT(*) as total')
|
|
->groupBy('comment_id', 'reaction')
|
|
->get()
|
|
->groupBy('comment_id');
|
|
|
|
$mine = collect();
|
|
if ($userId !== null) {
|
|
$mine = DB::table('comment_reactions')
|
|
->whereIn('comment_id', $ids)
|
|
->where('user_id', $userId)
|
|
->get(['comment_id', 'reaction'])
|
|
->groupBy('comment_id');
|
|
}
|
|
|
|
$result = [];
|
|
foreach ($ids as $commentId) {
|
|
$commentCounts = $counts->get($commentId, collect())->keyBy('reaction');
|
|
$commentMine = $mine->get($commentId, collect())->pluck('reaction')->flip();
|
|
|
|
$totals = [];
|
|
foreach (ReactionType::cases() as $type) {
|
|
$slug = $type->value;
|
|
$totals[$slug] = [
|
|
'emoji' => $type->emoji(),
|
|
'label' => $type->label(),
|
|
'count' => (int) ($commentCounts->get($slug)->total ?? 0),
|
|
'mine' => $commentMine->has($slug),
|
|
];
|
|
}
|
|
|
|
$result[$commentId] = $totals;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|