where('project_id', $project->id) ->findOrFail($linkedTicketId); $sourceTicket = $isSourceTicket ? $ticket : $linkedTicket; $targetTicket = $isSourceTicket ? $linkedTicket : $ticket; return DB::transaction(function () use ($linkedTicket, $user, $ticketLinkTypeId, $ticket, $sourceTicket, $targetTicket, $isSourceTicket): 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' => $sourceTicket->id, 'target_ticket_id' => $targetTicket->id, 'ticket_link_type_id' => $ticketLinkTypeId, ]); } else { $ticketLink->update([ 'source_ticket_id' => $sourceTicket->id, 'target_ticket_id' => $targetTicket->id, 'ticket_link_type_id' => $ticketLinkTypeId, ]); } $ticketLink->load('ticketLinkType'); $ticketLabel = $ticketLink->ticketLinkType->labelForSource($isSourceTicket); $linkedTicketLabel = $ticketLink->ticketLinkType->labelForSource(! $isSourceTicket); $this->createTicketWorklogEntry->handle( $ticket, $user, TicketWorklogEntryType::LinkUpdated, "Linked {$linkedTicket->ticket_key} as {$ticketLabel}.", [ 'linked_ticket_key' => $linkedTicket->ticket_key, 'ticket_link_type' => $ticketLabel, ], ); $this->createTicketWorklogEntry->handle( $linkedTicket, $user, TicketWorklogEntryType::LinkUpdated, "Linked {$ticket->ticket_key} as {$linkedTicketLabel}.", [ 'linked_ticket_key' => $ticket->ticket_key, 'ticket_link_type' => $linkedTicketLabel, ], ); return $ticketLink; }); } }