Attempt to fix N+1 issues
This commit is contained in:
@@ -24,6 +24,8 @@ final class TicketControlsController extends Controller
|
||||
*/
|
||||
public function updateAgent(Request $request, Ticket $ticket, WorkflowNotificationService $workflow): RedirectResponse
|
||||
{
|
||||
$ticket->loadMissing($this->ticketActionRelations());
|
||||
|
||||
Gate::authorize('update', $ticket);
|
||||
|
||||
$validated = $request->validate([
|
||||
@@ -48,7 +50,7 @@ final class TicketControlsController extends Controller
|
||||
'last_activity_at' => now(),
|
||||
]);
|
||||
|
||||
$fresh = $ticket->fresh(['agent.company', 'owner.company', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$workflow->dispatch($fresh, 'ticket.updated', Auth::user());
|
||||
|
||||
return redirect()
|
||||
@@ -63,6 +65,8 @@ final class TicketControlsController extends Controller
|
||||
*/
|
||||
public function updateStatus(Request $request, Ticket $ticket, WorkflowNotificationService $workflow, SlaService $sla): RedirectResponse
|
||||
{
|
||||
$ticket->loadMissing($this->ticketActionRelations());
|
||||
|
||||
Gate::authorize('update', $ticket);
|
||||
|
||||
$validated = $request->validate([
|
||||
@@ -79,7 +83,7 @@ final class TicketControlsController extends Controller
|
||||
|
||||
$this->ensureBoardContainsStatus($ticket, (int) $status->id);
|
||||
|
||||
$fresh = $ticket->fresh(['agent.company', 'owner.company', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
|
||||
if ($status->is_closed) {
|
||||
$sla->recordClosure($fresh);
|
||||
@@ -97,6 +101,8 @@ final class TicketControlsController extends Controller
|
||||
*/
|
||||
public function updatePriority(Request $request, Ticket $ticket, WorkflowNotificationService $workflow): RedirectResponse
|
||||
{
|
||||
$ticket->loadMissing($this->ticketActionRelations());
|
||||
|
||||
Gate::authorize('update', $ticket);
|
||||
|
||||
$validated = $request->validate([
|
||||
@@ -108,7 +114,7 @@ final class TicketControlsController extends Controller
|
||||
'last_activity_at' => now(),
|
||||
]);
|
||||
|
||||
$fresh = $ticket->fresh(['agent.company', 'owner.company', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
||||
$workflow->dispatch($fresh, 'ticket.updated', Auth::user());
|
||||
|
||||
return redirect()
|
||||
@@ -116,6 +122,25 @@ final class TicketControlsController extends Controller
|
||||
->with('ticket-action-updated', 'Priority updated to '.($fresh->priority?->name ?? 'selected priority').'.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relations needed by policies, redirect messages, and workflow templates.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private function ticketActionRelations(): array
|
||||
{
|
||||
return [
|
||||
'owner.company',
|
||||
'agent.company',
|
||||
'status',
|
||||
'priority',
|
||||
'category',
|
||||
'project',
|
||||
'team',
|
||||
'product',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a direct guarded ticket update without relying on Livewire hydration.
|
||||
*
|
||||
|
||||
@@ -224,7 +224,7 @@ final class TicketEdit extends Component
|
||||
$columns[] = 'company_id';
|
||||
}
|
||||
|
||||
$query = User::query()->select($columns)->orderBy('name');
|
||||
$query = User::query()->select($columns)->with('company')->orderBy('name');
|
||||
|
||||
if ($this->company_id !== null && Schema::hasColumn('users', 'company_id')) {
|
||||
$tenantUsers = (clone $query)
|
||||
@@ -248,8 +248,8 @@ final class TicketEdit extends Component
|
||||
private function freshTicket(Ticket $ticket): Ticket
|
||||
{
|
||||
return $ticket->fresh([
|
||||
'owner.company',
|
||||
'agent.company',
|
||||
'owner',
|
||||
'agent',
|
||||
'status',
|
||||
'priority',
|
||||
'category',
|
||||
|
||||
@@ -55,8 +55,7 @@ final class TicketShow extends Component
|
||||
|
||||
public function mount(Ticket $ticket): void
|
||||
{
|
||||
Auth::user()?->loadMissing('company');
|
||||
$ticket->loadMissing(['owner.company', 'agent.company']);
|
||||
$ticket->loadMissing($this->ticketDetailRelations());
|
||||
|
||||
$this->authorize('view', $ticket);
|
||||
$this->ticket = $this->freshTicket($ticket);
|
||||
@@ -262,6 +261,8 @@ final class TicketShow extends Component
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
$this->ticket = $this->freshTicket($this->ticket);
|
||||
|
||||
return view('helpdesk::livewire.ticket-show', [
|
||||
'statuses' => Status::query()->orderBy('sort_order')->get(),
|
||||
'priorities' => Priority::query()->orderBy('sort_order')->get(),
|
||||
@@ -282,9 +283,14 @@ final class TicketShow extends Component
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
private function freshTicket(Ticket $ticket): Ticket
|
||||
/**
|
||||
* Relations required by the ticket detail view and workflow renderers.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private function ticketDetailRelations(): array
|
||||
{
|
||||
$ticket = $ticket->fresh([
|
||||
return [
|
||||
'owner.company',
|
||||
'agent.company',
|
||||
'status',
|
||||
@@ -300,7 +306,12 @@ final class TicketShow extends Component
|
||||
'checklistItems',
|
||||
'attachments.user.company',
|
||||
'gitCommits.repository',
|
||||
]) ?? $ticket;
|
||||
];
|
||||
}
|
||||
|
||||
private function freshTicket(Ticket $ticket): Ticket
|
||||
{
|
||||
$ticket = $ticket->fresh($this->ticketDetailRelations()) ?? $ticket;
|
||||
|
||||
$comments = \Modules\Helpdesk\Models\Comment::query()
|
||||
->where('ticket_id', $ticket->id)
|
||||
|
||||
@@ -24,6 +24,21 @@ final class Ticket extends Model
|
||||
|
||||
protected $table = 'helpdesk_tickets';
|
||||
|
||||
|
||||
/**
|
||||
* Relations that are repeatedly displayed in ticket lists/detail views.
|
||||
*
|
||||
* Eager loading these user/company relations prevents the debug-bar N+1
|
||||
* detector from firing when Blade, policies, or workflow rendering read the
|
||||
* requester or assigned agent details.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $with = [
|
||||
'owner.company',
|
||||
'agent.company',
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
protected $fillable = [
|
||||
'reference', 'company_id', 'user_id', 'agent_id', 'status_id', 'board_id', 'priority_id', 'category_id', 'project_id', 'team_id',
|
||||
|
||||
@@ -193,14 +193,8 @@ versions:
|
||||
|
||||
"1.3.10":
|
||||
changed:
|
||||
- Fixed the ticket detail and ticket edit agent options queries by replacing unsupported orWhereKey usage with supported id comparisons.
|
||||
- Eager-loaded requester and agent company relations on the ticket detail/edit views to prevent Debugbar N+1 alerts.
|
||||
- Kept agent, status and priority persistence on CSRF-protected POST routes with compact action buttons.
|
||||
- Fixed ticket detail N+1 warnings by eager-loading requester, agent and company relations on ticket hydration, ticket refresh and ticket control POST actions.
|
||||
- Added default eager loading for Helpdesk ticket requester and assigned-agent company details to prevent repeated lazy user/company queries in detail and list views.
|
||||
- Replaced remaining unsupported orWhereKey usage with supported id predicates in ticket assignment option queries.
|
||||
- Kept agent, status and priority controls as compact CSRF-protected POST forms that persist directly to helpdesk_tickets.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
"1.3.11":
|
||||
changed:
|
||||
- Eager-loaded the current user company, ticket requester company, ticket agent company, comment user company and attachment user company on the ticket detail page to remove the remaining Debugbar N+1 alert.
|
||||
- Eager-loaded company data for assignable agent dropdown users without changing agent, status or priority persistence behaviour.
|
||||
- Kept module.json version in sync with changelog.yaml.
|
||||
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.3.11"
|
||||
"version": "1.3.10"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user