Vlastné polia
Správcovia definujú polia v databáze (ticket_fields) — globálne, pre projekt alebo pre kategóriu; hodnoty žijú v attributes-for-laravel, jedna na (tiket, kľúč). define(FieldData) je DTO podoba buildera; obe spúšťajú DefineFieldAction a settery buildera validujú hneď:
use RoundlyConsulting\Tickets\DataTransferObjects\UpdateFieldData;
use RoundlyConsulting\Tickets\Enums\FieldType;
Tickets::fields()->make('asset_tag', FieldType::Text)
->label(['en' => 'Asset tag', 'sk' => 'Inventárne číslo'])
->help(['en' => 'On the sticker'])
->category($hardware) // or ->project($helpdesk); neither = global
->required()
->requesterEditable() // the requester may fill it (implies requester-visible)
->rules(['max:32'])
->define();
Tickets::fields()->make('root_cause', FieldType::Select)
->options(['hardware' => ['en' => 'Hardware'], 'user' => ['en' => 'User error']])
->agentOnly() // requester_visible = false, requester_editable = false
->define();
Tickets::fields()->update($field, new UpdateFieldData(required: false, position: 5));
Tickets::fields()->delete($field); // soft: values stay hidden until a restore or a prune
Tickets::fields()->restore($field); // refused when the key was taken meanwhile| Atribút | Význam |
|---|---|
key | ^[a-z][a-z0-9_]{0,63}$; nemenný. Unikátny medzi živými poliami projektu vrátane globálnych polí a všetkých kategórií — podkategória nemôže znova definovať kľúč predka ani globálny kľúč. Odmietne sa aj kľúč, pod ktorým zmazané pole daného rozsahu stále drží hodnoty (field.kept_values): pole obnovte alebo najprv jeho hodnoty vyčistite. Vynucuje sa pod poradným zámkom lock:fields. |
label, help | Preložiteľné mapy jazykov (reťazec = aktuálny jazyk). |
type | FieldType (nižšie). |
options | select / multiselect: hodnota => popis (mapa jazykov alebo reťazec). |
rules | Ďalšie pravidlá z tickets.fields.allowed_rules. |
required, default, encrypted | Predvolená hodnota musí byť hodnota, ktorú pole samo prijme (typ, možnosti, pravidlá) — kontroluje sa pri define() aj pri každej úprave; inak ValidationException s kľúčom default (HTTP 422). |
requester_visible, requester_editable | Čo strana žiadateľa vidí a smie nastaviť. |
position, is_active | Poradie; neaktívne pole sa neponúka, jeho hodnoty zostávajú. |
| project, category_id | Nemenný rozsah. |
Typy polí
| FieldType | Ukladá sa ako | Základné pravidlá |
|---|---|---|
text | string | string, max:255 |
textarea | string | string, max:65535 |
email | string | string, email:rfc |
url | string | string, url |
number | integer | integer |
decimal | float | numeric |
boolean | boolean | boolean |
date, datetime | datetime | date |
select | string | string, in:<options> |
multiselect | array | array, každá in:<options> |
Pravidlá sú len z povoleného zoznamu (tickets.fields.allowed_rules): exists a unique sa odmietnu vždy (žiadne skúmanie databázy), rovnako closures a objekty, a vzor regex: má najviac 255 znakov a musí sa dať skompilovať. Keď existujú hodnoty, typ aj príznak šifrovania sa uzamknú (FieldTypeLockedException); možnosti select potom môžu len pribúdať a multiselect si ponechá každú používanú možnosť.
Platná sada polí
Polia tiketu sú aktívne polia, ktorých projekt je projekt tiketu (alebo globálny) a ktorých kategória je null alebo leží v reťazi predkov kategórie tiketu, zoradené podľa position. Fields\FieldSetResolver (scoped na požiadavku či job, bezpečný pre Octane) si sadu zapamätá pre (projekt, kategória):
Tickets::fields()->for($ticket); // array<string, FieldDefinition>, keyed by field key
Tickets::fields()->for($category, $project); // for a ticket that would be filed there
Tickets::for($ticket)->fields()->definitions();
Tickets::fields()->find('asset_tag', $project); // ?TicketField by key or id: the project's, else the global oneHodnoty
Tickets::for($ticket)->by($agent)->fields()->set('asset_tag', 'PRN-0042')->setMany(['root_cause' => 'hardware']);
Tickets::for($ticket)->fields()->get('asset_tag'); // the default when unset; null for an unknown key
Tickets::for($ticket)->fields()->all(); // ['asset_tag' => 'PRN-0042', …], field order
Tickets::for($ticket)->by($agent)->fields()->forget(['root_cause']);
Tickets::make()->subject('…')->requester($user)->category($hardware)->fields(['asset_tag' => 'PRN-0042'])->create();- set($key, null) hodnotu zruší; zrušenie či zabudnutie povinného poľa sa odmietne (ValidationException).
- Kľúč, ktorý nie je poľom tiketu, vyhodí FieldNotEditableException (unknown_field); aktér, ktorý nie je agent, smie nastaviť len polia requester_editable (field_not_editable).
- Každá hodnota sa zvaliduje podľa svojho poľa (ValidationException s kľúčom fields.<key>) a hlásenie pomenuje pole jeho popisom v aktuálnom jazyku.
- Povinné polia sa vynucujú pri založení, keď zmena kategórie prinesie novo povinné pole, a keď hodnoty polí zapisuje agent alebo systém — vždy len to, čo smie aktér zapisovať, takže povinné pole len pre agentov nezablokuje samoobsluhu.
- Interný záznam aktivity fields_changed a TicketFieldsChanged nesú zmenené kľúče — nikdy hodnoty, takže šifrované hodnoty sa nedostanú do histórie, udalostí ani logov.
- Hodnoty zmazaného poľa alebo poľa, ktoré po zmene kategórie už neplatí, zostanú uložené, no pri čítaní skryté; pod iným poľom sa nikdy neobjavia.
Viditeľnosť
Resources pre žiadateľov a hostí ukazujú len polia requester_visible. Šifrované hodnoty sa agentom dešifrujú; žiadateľ šifrovanú hodnotu uvidí, len ak je pole requester_visible.
Filtrovanie
Ticket::query()->whereField('asset_tag', 'PRN-0042')->get();
Ticket::query()->whereFieldBetween('estimate_hours', 2, null)->get(); // one-sided: the open end is padded- Hodnota sa najprv prevedie na typ poľa (reťazec „42“ z požiadavky nájde celočíselný riadok); hodnota, ktorú previesť nemožno, nenájde nič.
- Obe hranice sú inkluzívne. Horná hranica poľa datetime zadaná ako dátum (2026-10-17) platí do konca dňa.
- Neznámy, šifrovaný alebo multiselect kľúč vyhodí UnknownTicketFieldException.
- V API: filter[fields.<key>]=a,b a pre polia number, decimal, date a datetime filter[fields.<key>.from] / filter[fields.<key>.to] — zostavené pri každej požiadavke z aktívnych, nešifrovaných polí, ktoré nie sú multiselect a ktoré divák smie vidieť.
Čistenie osirotených hodnôt
$count = Tickets::fields()->prune(dryRun: true); // count only
$count = Tickets::fields()->prune(chunk: 500); // forget them, 500 tickets at a timephp artisan tickets:prune-fields --dry-run
php artisan tickets:prune-fields --chunk=500Čistenie natrvalo zmaže hodnoty, ktoré už nezodpovedajú žiadnemu poľu ich tiketu — zmazanému poľu alebo kategórii, ktorú tiket opustil. Hodnoty neaktívneho poľa zostanú. Je to jediný krok, ktorý sa nedá vrátiť; dovtedy ich obnovenie poľa vráti a definícia nového poľa s kľúčom zmazaného poľa sa odmieta, kým také hodnoty existujú.
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 kryptomienOdoslaní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.