---
title: "Modely, kľúče a čísla tiketov — Tickets for Laravel | Roundly"
description: "Typy kľúčov, čísla tiketov bez medzier a postupnosti, deväť modelov, stĺpce modelu Ticket, pomocníci stavov a meta hostiteľa, výmena modelov a enumy."
url: https://roundly-consulting.com/sk/open-source/navody/tickets-for-laravel/modely-a-kluce
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Tickets for Laravel](https://roundly-consulting.com/sk/open-source/navody/tickets-for-laravel.md)

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

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

| Nastavenie | Kľúčuje | Musí sa rovnať |
| --- | --- | --- |
| `tickets.primary_key_type` | Primá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_type` | Id 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

| Model | Tabuľka | Vymeniteľný | Soft delete |
| --- | --- | --- | --- |
| `Ticket` | `tickets` | `tickets.models.ticket` | áno |
| `TicketCategory` | `ticket_categories` | `tickets.models.category` | áno |
| `TicketField` | `ticket_fields` | `tickets.models.field` | áno |
| `TicketTag` | `ticket_tags` | `tickets.models.tag` | áno |
| `TicketGuest` | `ticket_guests` | `tickets.models.guest` | áno |
| `TicketWatcher` | `ticket_watchers` | nie (final) | nie — unikátne riadky |
| `TicketLink` | `ticket_links` | nie (final) | nie — unikátne riadky |
| `TicketActivity` | `ticket_activities` | nie (final) | nie — len pripisovanie |
| `TicketSequence` | `ticket_sequences` | nie (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ĺpce | Význam |
| --- | --- |
| `id, reference, number, sequence_scope` | Identita. |
| `subject, description` | Obsah. |
| `status` | Patrí balíku lifecycle — tickets ho nikdy nezapisuje (lifecycle.strict\_writes zostáva zapnuté). |
| `priority` | Hodnota enumu priorít (string 32). |
| `category_id` | Cudzí kľúč, pri zmazaní null. |
| `requester_type/_id, assignee_type/_id, assigned_at, project_type/_id, channel` | Zúč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_version` | Cieľ zlúčenia; verzia odkazov pre hostí. |
| `meta` | JSON 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ík | Pravda, keď | Scope |
| --- | --- | --- |
| `isUnresolved()` | Open, Active alebo Waiting | `unresolved()` |
| `isResolved()` | v stave kategórie Resolved | `withStatusCategory(StatusCategory::Resolved)` |
| `isClosed()` | v stave kategórie Closed | `withStatusCategory(StatusCategory::Closed)` |
| `isOverdue()` | po termíne (striktne) a nevyriešený | `overdue()` |
| `isMerged()` | zlúčený do iného tiketu | `merged()` |
| `isAssigned()` | má riešiteľa | opak unassigned() |

```php
$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:

```php
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

```php
// 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

| Enum | Hodnoty | Pomocníci |
| --- | --- | --- |
| `TicketStatus` | `new, open, in_progress, pending, on_hold, resolved, closed` | `category(): StatusCategory` |
| `StatusCategory` | `open, active, waiting, resolved, closed` | `isUnresolved(), static unresolved()` |
| `Automation` | `assigned, requester_replied, requester_reopened, auto_close, merged` | `sources(), targets()` |
| `TicketPriority` | `low (10), normal (20), high (30), urgent (40)` | `weight(): int` |
| `FieldType` | `text, textarea, email, url, number, decimal, boolean, date, datetime, select, multiselect` | `attributeType(), hasOptions()` |
| `LinkType` | `relates_to, duplicates, blocks, parent_of` | `inverse(), inverseLabel(), isSymmetric(), isAcyclic()` |
| `ActivityType` | pozrite Vyhľadávanie a história aktivít | `defaultVisibility()` |
| `ActivityVisibility` | `public, internal` | — |
| `AuthorRole` | `agent, requester, participant, system` | — |
| `TicketChannel` | `web, email, api, phone, chat` | popis a farba dodaného kanála |
| `NotificationType` | `created, assigned, replied, requester_replied, note_added, mentioned, status_changed, overdue, due_soon, merged` | `defaultClass(), reachesRequesters()` |
| `TicketOperation` | kaž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](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## 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.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/tickets-for-laravel.md)
