where('project_id', $project->id) ->findOrFail($linkedTicketId); return DB::transaction(function () use ($linkedTicket, $user, $ticketLinkTypeId, $ticket): TicketLink { Ticket::query() ->whereKey([$ticket->id, $linkedTicket->id]) ->orderBy('id') ->lockForUpdate() ->get(['id']); $ticketLink = TicketLink::query() ->where(function ($query) use ($ticket, $linkedTicket): void { $query ->where('source_ticket_id', $ticket->id) ->where('target_ticket_id', $linkedTicket->id); }) ->orWhere(function ($query) use ($ticket, $linkedTicket): void { $query ->where('source_ticket_id', $linkedTicket->id) ->where('target_ticket_id', $ticket->id); }) ->first(); if ($ticketLink === null) { $ticketLink = TicketLink::query()->create([ 'source_ticket_id' => $ticket->id, 'target_ticket_id' => $linkedTicket->id, 'ticket_link_type_id' => $ticketLinkTypeId, ]); } else { $ticketLink->update([ 'source_ticket_id' => $ticket->id, 'target_ticket_id' => $linkedTicket->id, 'ticket_link_type_id' => $ticketLinkTypeId, ]); } $ticketLink->load('ticketLinkType'); $sourceLabel = $ticketLink->ticketLinkType->labelForSource(true); $targetLabel = $ticketLink->ticketLinkType->labelForSource(false); $this->createTicketWorklogEntry->handle( $ticket, $user, TicketWorklogEntryType::LinkUpdated, "Linked {$linkedTicket->ticket_key} as {$sourceLabel}.", [ 'linked_ticket_key' => $linkedTicket->ticket_key, 'ticket_link_type' => $sourceLabel, ], ); $this->createTicketWorklogEntry->handle( $linkedTicket, $user, TicketWorklogEntryType::LinkUpdated, "Linked {$ticket->ticket_key} as {$targetLabel}.", [ 'linked_ticket_key' => $ticket->ticket_key, 'ticket_link_type' => $targetLabel, ], ); return $ticketLink; }); } }