NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Tickets for Laravel

Modely, kľúče a čísla tiketov

Dve nastavenia, ktoré čítajú migrácie — nastavte ich pred migráciou:

NastavenieKľúčujeMusí sa rovnať
tickets.primary_key_typePrimárny kľúč tabuliek tickets a ticket_guests — modelov, na ktoré ukazujú ostatné balíky (subjekt lifecycle, komentovaný model, vlastník atribútov a médií) — a každý stĺpec, ktorý ukazuje na tiket (ticket_tag.ticket_id, ticket_watchers.ticket_id, ticket_links.ticket_id / related_ticket_id, ticket_activities.ticket_id, tickets.merged_into_id).lifecycle.key_type, attributes.key_type, comments.key_type
tickets.key_typeId polymorfných vzťahov smerom von: žiadateľ, riešiteľ, projekt, sledujúci, aktér v histórii, autor prepojenia, predvolený riešiteľ kategórie.typ kľúča vášho modelu používateľa, lifecycle.actor_key_type, comments.key_type

Pri uuid alebo ulid generujú Ticket a TicketGuest časovo zoradené kľúče (UUIDv7 / ULID) cez Concerns\HasConfigurableKey. Všetky ostatné tabuľky balíka si ponechajú bigint id() a polymorfné stĺpce idú cez morphKey / ownerKey z toolkitu. media.model_id je reťazcový stĺpec, takže media-library žiadne nastavenie kľúča nepotrebuje. tickets:doctor nahlási každú dvojicu, ktorá nesedí, a upozorní, keď má model používateľa predvoleného guardu iný typ kľúča ako tickets.key_type.

Čísla tiketov a postupnosti

  • Číslo tiketu má tvar {prefix}-{number} — TCK-42, v projekte SUP-42. Prefix je tickets.reference.prefix, pri tikete v projekte TicketProject::ticketReferencePrefix(); oba musia zodpovedať ^[A-Z][A-Z0-9]{0,9}$.
  • Jedna postupnosť pre tikety bez projektu (rozsah global) a jedna pre každý projekt (rozsah {morphAlias}:{key}), uložené na tikete ako sequence_scope + number, spolu unikátne. Číslo tiketu je uložené, unikátne a slúži ako kľúč routy.
  • Čísla sú bez medzier aj pri súbežnosti: riadok postupnosti sa v transakcii založenia číta so zámkom. Vrátené založenie svoje číslo uvoľní; soft-deleted tiket si číslo ponechá; čísla sa nikdy nepoužijú znova.
  • Projekt, ktorý zmení prefix, si ponechá staré čísla; nové tikety pokračujú v tej istej postupnosti s novým prefixom.
  • Dva projekty s rovnakým prefixom sa zrazia na čísle — DuplicateTicketReferenceException. Prefixy musia byť unikátne.

Modely

ModelTabuľkaVymeniteľnýSoft delete
Ticketticketstickets.models.ticketáno
TicketCategoryticket_categoriestickets.models.categoryáno
TicketFieldticket_fieldstickets.models.fieldáno
TicketTagticket_tagstickets.models.tagáno
TicketGuestticket_gueststickets.models.guestáno
TicketWatcherticket_watchersnie (final)nie — unikátne riadky
TicketLinkticket_linksnie (final)nie — unikátne riadky
TicketActivityticket_activitiesnie (final)nie — len pripisovanie
TicketSequenceticket_sequencesnie (final)nie

Model Ticket

Ticket implementuje LifecycleSubject z lifecycle (HasLifecycle, atribút status), HasComments z comments, HasAttributes z attributes (importované ako HasCustomFields) a HasMedia z media-library (InteractsWithMedia). Ich metódy sa nekryjú.

StĺpceVýznam
id, reference, number, sequence_scopeIdentita.
subject, descriptionObsah.
statusPatrí balíku lifecycle — tickets ho nikdy nezapisuje (lifecycle.strict_writes zostáva zapnuté).
priorityHodnota enumu priorít (string 32).
category_idCudzí kľúč, pri zmazaní null.
requester_type/_id, assignee_type/_id, assigned_at, project_type/_id, channelZúčastnené strany.
due_at, due_soon_notified_at, overdue_notified_at, first_responded_at, resolved_at, closed_at, last_activity_atČasovanie (resolved_at / closed_at sú pečiatky z lifecycle).
merged_into_id, guest_access_versionCieľ zlúčenia; verzia odkazov pre hostí.
metaJSON pre vás — balík ho nikdy nezapisuje a nikdy ho neukáže v API.

Vzťahy: category(), requester(), assignee(), project(), mergedInto(), tags(), watchers() (riadky TicketWatcher), links(), activities() — a z traitov comments(), media(), vzťahy lifecycle a vzťahy atribútov. Skratky, ktoré idú cez manažéra, takže ich vidí aj fake: reply($body, ?$author), note($body, ?$author) a assignTo($assignee, ?$actor).

Pomocníci stavov

Každý pomocník sa zhoduje so svojím query scope, takže odznak a filter v zozname sa nikdy nerozídu:

PomocníkPravda, keďScope
isUnresolved()Open, Active alebo Waitingunresolved()
isResolved()v stave kategórie ResolvedwithStatusCategory(StatusCategory::Resolved)
isClosed()v stave kategórie ClosedwithStatusCategory(StatusCategory::Closed)
isOverdue()po termíne (striktne) a nevyriešenýoverdue()
isMerged()zlúčený do iného tiketumerged()
isAssigned()má riešiteľaopak unassigned()
$ticket->priority();         // TicketPriority::High — null for a value the enum no longer has
$ticket->statusCategory();   // StatusCategory::Waiting
$ticket->isUnresolved();     // Open, Active or Waiting
$ticket->isOverdue();        // past its due date (strictly) and unresolved
$ticket->isMerged();         // merged into another ticket

Meta hostiteľa

meta(?string $path = null, mixed $default = null) vráti celú mapu alebo hodnotu podľa bodkovej cesty a hasMeta(string $path) povie, či kľúč existuje. Použite ich na id vašich integrácií — id v CRM, zdrojovú URL:

use RoundlyConsulting\Tickets\DataTransferObjects\UpdateTicketData;

$ticket = Tickets::make()->subject('…')->requester($user)->meta(['crm_id' => 'C-1'])->create();

$ticket->meta();                  // ['crm_id' => 'C-1']
$ticket->meta('crm_id');          // 'C-1'
$ticket->hasMeta('crm_id');       // true — a key holding null counts as present

// Replaces the whole map; [] clears it
Tickets::for($ticket)->update(new UpdateTicketData(meta: ['crm_id' => 'C-2']));

TicketBuilder::meta() pri opakovaných volaniach zlúči kľúče najvyššej úrovne; UpdateTicketData(meta: …) nahradí celú mapu. Meta sa nikdy nedostane do API resource, zmena sa zaznamená ako interný záznam updated s názvom kľúča meta (nikdy s hodnotou) a zmena len meta nechá verejné updated_at nedotknuté.

Ostatné modely

  • TicketCategory — strom (parent_id, pri zmazaní null) s voliteľným projektom; preložiteľné name a description; slug vytvorený raz z názvu v záložnom jazyku, unikátny medzi súrodencami v rámci projektu; position, is_active a predvolené hodnoty default_priority, default_assignee (morph) a default_due_in (ISO-8601).
  • TicketField — definícia vlastného poľa: key, preložiteľné label a help, type (FieldType), options, rules, required, encrypted, default, requester_visible, requester_editable, position, is_active, projekt a category_id.
  • TicketTag — name (1–64 znakov, v rámci rozsahu trvalý), slug (unikátny v projekte, nasleduje premenovanie), color (#rrggbb, uložené malými písmenami) a projekt; pivot ticket_tag.
  • TicketGuest — žiadne pevné stĺpce s osobnými údajmi: každé pole z tickets.guests.fields sa ukladá cez attributes-for-laravel. displayName() číta pole display, routeNotificationFor($driver) pole, ktorého route je daný driver; vzťahy requestedTickets() a watchedTickets().
  • TicketActivity — len pripisovanie (úprava či zmazanie vyhodí ActivityIsAppendOnlyException): ticket_id, type, aktér (morph), is_system, visibility, properties (rozdiel — nikdy text poznámky ani šifrovaná hodnota) a occurred_at.
  • TicketWatcher, TicketLink, TicketSequence — final, čítajú sa cez handly; TicketSequence drží aj poradné zámky balíka (lock:categories, lock:tags, lock:fields, lock:links). Nikdy doň nezapisujte sami.

Výmena modelu

// config/tickets.php
'models' => [
    'ticket' => App\Models\SupportTicket::class,   // extends RoundlyConsulting\Tickets\Models\Ticket
    // …
],

Nastavte to v konfigurácii, nie za behu: provider pri štarte napojí listenery na nakonfigurovanú triedu. Každý dopyt, vzťah, listener aj factory balíka získavajú triedu cez Support\TicketModels, takže sa vráti vaša podtrieda. Hooky, ktoré volajú podkladové balíky — getRouteKeyName() (reference), lifecycleDefinitions(), attributeDefinitions() a registerMediaBuckets() —, prepisujte len so zavolaním parent.

Tabuľky

Desať migrácií, ktoré sa len publikujú a idú len dopredu, v poradí cudzích kľúčov: ticket_categories → ticket_sequences → ticket_guests → tickets → ticket_fields → ticket_tags → ticket_tag → ticket_watchers → ticket_links → ticket_activities. Tikety sa mažú soft, takže ich kaskády sa spustia len pri force delete. Preložiteľné stĺpce používajú makro z translatable-for-laravel (jsonb v PostgreSQL, json v MySQL); meta, options, rules, default a properties sú obyčajné jsonb. Balík zapisuje aj do tabuliek balíkov comments (konverzácia), lifecycle (história stavov), attributes (hodnoty vlastných polí a hostí) a media-library (prílohy).

Enumy

EnumHodnotyPomocníci
TicketStatusnew, open, in_progress, pending, on_hold, resolved, closedcategory(): StatusCategory
StatusCategoryopen, active, waiting, resolved, closedisUnresolved(), static unresolved()
Automationassigned, requester_replied, requester_reopened, auto_close, mergedsources(), targets()
TicketPrioritylow (10), normal (20), high (30), urgent (40)weight(): int
FieldTypetext, textarea, email, url, number, decimal, boolean, date, datetime, select, multiselectattributeType(), hasOptions()
LinkTyperelates_to, duplicates, blocks, parent_ofinverse(), inverseLabel(), isSymmetric(), isAcyclic()
ActivityTypepozrite Vyhľadávanie a história aktivítdefaultVisibility()
ActivityVisibilitypublic, internal—
AuthorRoleagent, requester, participant, system—
TicketChannelweb, email, api, phone, chatpopis a farba dodaného kanála
NotificationTypecreated, assigned, replied, requester_replied, note_added, mentioned, status_changed, overdue, due_soon, mergeddefaultClass(), reachesRequesters()
TicketOperationkaždá operácia, ktorú fake zaznamená — jedna na cestu manažéra—

Každý enum má reťazcové hodnoty, implementuje HasColor z enums-for-laravel (color(): názov z palety, napríklad blue, amber či red) a používa jeho trait Helpers: label() (preložené cez tickets::enums.<enum>.<value>, v angličtine a slovenčine), labels(), values(), options(), toOptions(), validationRule(), tryFromName(), is() / isIn() a ostatné metódy traitu.

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.