fixed N+1 issues
This commit is contained in:
@@ -11,7 +11,8 @@ final class CannedResponseRenderer
|
||||
{
|
||||
public function render(string $template, Ticket $ticket, ?User $actor = null): string
|
||||
{
|
||||
$ticket->loadMissing(['user.company', 'owner.company', 'agent.company', 'status', 'priority', 'category', 'project', 'team']);
|
||||
$this->hydrateTicketUsers($ticket);
|
||||
$ticket->loadMissing(['status', 'priority', 'category', 'project', 'team']);
|
||||
$actor?->loadMissing('company');
|
||||
|
||||
return strtr($template, [
|
||||
@@ -28,4 +29,42 @@ final class CannedResponseRenderer
|
||||
'{{ ticket.url }}' => route('helpdesk.tickets.show', ['ticket' => $ticket->getKey()]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load requester/agent with one query if the caller has not already attached them.
|
||||
*/
|
||||
private function hydrateTicketUsers(Ticket $ticket): void
|
||||
{
|
||||
if ($ticket->relationLoaded('owner') && $ticket->relationLoaded('agent')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$userIds = collect([$ticket->user_id, $ticket->agent_id])
|
||||
->filter()
|
||||
->map(static fn (mixed $id): int => (int) $id)
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($userIds->isEmpty()) {
|
||||
$ticket->setRelation('user', null);
|
||||
$ticket->setRelation('owner', null);
|
||||
$ticket->setRelation('agent', null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$users = User::query()
|
||||
->with('company')
|
||||
->whereIn('id', $userIds)
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
$owner = $users->get((int) $ticket->user_id);
|
||||
$agent = $ticket->agent_id === null ? null : $users->get((int) $ticket->agent_id);
|
||||
|
||||
$ticket->setRelation('user', $owner);
|
||||
$ticket->setRelation('owner', $owner);
|
||||
$ticket->setRelation('agent', $agent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ final class TicketService
|
||||
$this->checklists->applyTemplates($ticket);
|
||||
$this->attachments->storeMany($ticket, $files, (int) $user->id);
|
||||
|
||||
$ticket = $ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team', 'product', 'tags', 'attachments', 'checklistItems']) ?? $ticket;
|
||||
$ticket = $ticket->fresh(['status', 'priority', 'category', 'project', 'team', 'product', 'tags', 'attachments', 'checklistItems']) ?? $ticket;
|
||||
$this->workflow->dispatch($ticket, 'ticket.created', $user);
|
||||
|
||||
return $ticket;
|
||||
@@ -117,7 +117,7 @@ final class TicketService
|
||||
$this->sla->recordPublicResponse($ticket, $user);
|
||||
}
|
||||
$this->attachments->storeMany($ticket, $files, (int) $user->id, $comment);
|
||||
$this->workflow->dispatch($ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team']) ?? $ticket, $parentId === null ? 'ticket.commented' : 'ticket.reply_created', $user);
|
||||
$this->workflow->dispatch($ticket->fresh(['status', 'priority', 'category', 'project', 'team']) ?? $ticket, $parentId === null ? 'ticket.commented' : 'ticket.reply_created', $user);
|
||||
|
||||
return $comment->fresh(['user', 'attachments']) ?? $comment;
|
||||
});
|
||||
@@ -136,7 +136,7 @@ final class TicketService
|
||||
'last_activity_at' => now(),
|
||||
])->save();
|
||||
|
||||
$ticket = $ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$ticket = $ticket->fresh(['status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$this->sla->recordClosure($ticket);
|
||||
$this->workflow->dispatch($ticket, 'ticket.closed', $user);
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ final class WorkflowNotificationService
|
||||
*/
|
||||
public function dispatch(Ticket $ticket, string $event, ?User $actor = null): void
|
||||
{
|
||||
$ticket->loadMissing(['user.company', 'owner.company', 'agent.company', 'status', 'priority', 'category', 'project', 'team', 'product']);
|
||||
$this->hydrateTicketUsers($ticket);
|
||||
$ticket->loadMissing(['status', 'priority', 'category', 'project', 'team', 'product']);
|
||||
$actor?->loadMissing('company');
|
||||
|
||||
WorkflowTemplate::query()
|
||||
@@ -64,6 +65,43 @@ final class WorkflowNotificationService
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load requester/agent with one query if the caller has not already attached them.
|
||||
*/
|
||||
private function hydrateTicketUsers(Ticket $ticket): void
|
||||
{
|
||||
if ($ticket->relationLoaded('owner') && $ticket->relationLoaded('agent')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$userIds = collect([$ticket->user_id, $ticket->agent_id])
|
||||
->filter()
|
||||
->map(static fn (mixed $id): int => (int) $id)
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($userIds->isEmpty()) {
|
||||
$ticket->setRelation('user', null);
|
||||
$ticket->setRelation('owner', null);
|
||||
$ticket->setRelation('agent', null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$users = User::query()
|
||||
->with('company')
|
||||
->whereIn('id', $userIds)
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
$owner = $users->get((int) $ticket->user_id);
|
||||
$agent = $ticket->agent_id === null ? null : $users->get((int) $ticket->agent_id);
|
||||
|
||||
$ticket->setRelation('user', $owner);
|
||||
$ticket->setRelation('owner', $owner);
|
||||
$ticket->setRelation('agent', $agent);
|
||||
}
|
||||
|
||||
private function recipient(string $role, Ticket $ticket, ?User $actor): ?User
|
||||
{
|
||||
return match ($role) {
|
||||
|
||||
Reference in New Issue
Block a user