Fasáda Events
Všetko ide cez jednu fasádu, RoundlyConsulting\Events\Facades\Events — skratku nad singletonom EventsManager, bez globálneho aliasu. Miesto konania, kategória, podujatie s dvoma typmi vstupeniek, RSVP, skenovanie pri vstupe a hľadanie v okolí:
use RoundlyConsulting\Events\Facades\Events;
use RoundlyConsulting\Money\Money;
// A reusable venue: its timezone is how every wall-clock time below is read
$venue = Events::venues()->make('Blue Note')
->address(street: 'Hlavná 1', city: 'Bratislava', postalCode: '811 01', country: 'SK')
->coordinates(48.1439, 17.1097)
->timezone('Europe/Bratislava')
->create();
Events::categories()->make(['en' => 'Jazz', 'sk' => 'Jazz'])->create(); // categories are curated
$event = Events::make(['en' => 'Jazz Night', 'sk' => 'Jazzový večer'])
->description(['en' => 'A live quartet, then an open jam session.'])
->organizedBy($user)
->at($venue)
->startsAt('2026-11-14 20:00') // 20:00 in Bratislava, stored as UTC
->duration('3 hours') // or 'PT3H', a CarbonInterval, or ->endsAt(...)
->capacity(120)
->category('jazz')
->labels(['Live', 'Late night'])
->poster($request->file('poster'))
->tier('Free entry', key: 'free')
->tier('Supporter', price: Money::ofMajor('15', 'EUR'), capacity: 30) // key "supporter"
->publish();
// RSVP: a seat while there is one, the waitlist once it is full
$rsvp = Events::for($event)->rsvp($attendee)->going(tier: 'free');
$rsvp->isGoing(); // or isWaitlisted(), isHeld()
// At the door: scan the attendee's QR code, as the signed-in staff member
$result = Events::for($event)->by($doorStaff)->checkIn($scannedCode); // organizers and co-hosts only
$result->firstCheckIn; // false if the code was already used
// Discovery: upcoming published events (cancelled ones flagged by phase) within 25 km, nearest first
Events::browse()->upcoming()->near($here, km: 25)->orderByDistance($here)->paginate();Metódy manažéra
| Metóda | Vracia | Čo robí |
|---|---|---|
make(array|string $title) | EventBuilder | Fluentný builder; mapa jazykov alebo reťazec v aktuálnom jazyku. |
create(CreateEventData $data) | Event | Koncept — tá istá cesta kódu ako builder. |
find(string $uuid) | ?Event | Len živé podujatia; chybné uuid je null bez dotazu; bez pravidla viditeľnosti. |
findOrFail(string $uuid) | Event | Inak EventNotFoundException. |
findBySlug(string $slug, ?Model $viewer = null) | ?Event | Podľa reťazca jazykov; null pre podujatia len cez odkaz, súkromné podujatia a koncepty, ktoré $viewer bez odkazu vidieť nesmie. |
for(Event|string $event) | EventHandle | Podľa modelu alebo uuid; neznáme alebo zmazané uuid vyhodí EventNotFoundException. |
browse(?Model $viewer = null) | Builder<Event> | Viditeľné pre $viewer, verejne uvedené a ohlásené; vopred načíta venue, organizer, tiers, media a tags. |
visibleTo(?Model $viewer) | Builder<Event> | View z policy ako dotaz — vrátane konceptov a súkromných podujatí, ktoré divák spravuje. |
venues() | Accessors\Venues | Miesta konania — nižšie. |
categories() / labels() | Tags\Handles\TypeTags | Handle z tags-for-laravel pre events:category / events:label, bez úprav. |
rsvps() | Accessors\Rsvps | Platby, rezervácie, kódy a QR — nižšie. |
invitations() | Accessors\Invitations | Odpoveď z odkazu v pozvánke — nižšie. |
checkIn(string $code, Model $by, ?int $guests = null, bool $ignoreWindow = false) | CheckInResult | Skenovanie bez určenia podujatia — kód si podujatie nájde sám. |
ics(iterable $events, ?Model $viewer = null) | IcsCalendar | Kalendárový súbor; vynechá podujatia, ktoré $viewer vidieť nesmie. |
feeds() | Calendar\Feeds | public(EventFeedQuery) a for($attendee, includePrivate:). |
jsonLd(Event $event) | ?array | Dáta schema.org alebo null. |
sweep(?SweepOptions $options = null) | SweepResult | To, čo spúšťa events:sweep. |
repair(?RepairOptions $options = null) | RepairReport | To, čo spúšťa events:repair. |
Events::fake() | EventsFake | Len na fasáde — nahrávací fake, ktorý volania aj tak vykoná (pozrite Testovanie). |
forgetAttendee(), container() a perform() sú verejné pre vnútorné prepojenie balíka a označené ako @internal — z kódu aplikácie ich nevolajte.
Handle for($event)
Events::for($event) vráti nemenný EventHandle. by($actor) pred každým ďalším volaním overí policy podujatia, asSystem() beží ako dôveryhodný kód a silently() zapisuje bez notifikácií — každá z týchto metód vráti nový handle. Bez by() je volanie dôveryhodným PHP (úloha, seeder, príkaz) a policy sa nepýta. Mutátor vráti handle, takže volania sa dajú reťaziť; metóda, ktorá niečo vytvára alebo číta, vráti svoj výsledok. Naviazané podujatie sa aktualizuje na mieste, takže event() vráti aktuálny stav:
$handle = Events::for($event)->by($organizer); // checks the policy before every call
$handle->tiers()->add('Crew', hidden: true, key: 'crew');
$handle->hosts()->add($partnerTeam);
$handle->publish()->event(); // a mutator returns the handle; event() is the bound, current model
Events::for($event)->asSystem()->postpone('Storm warning'); // trusted code: no actor, no policy
Events::for($event)->silently()->reschedule('2026-12-05 20:00'); // domain events still fire, no notices| Metóda | Vracia | Oprávnenie (s by()) |
|---|---|---|
by(?Model $actor) | EventHandle | — |
asSystem() | EventHandle | — (bez aktéra, bez policy) |
silently() | EventHandle | — (doménové udalosti sa spustia, notifikácie nie) |
event() | Event | — |
update(UpdateEventData $data) | static | update |
edit() | EventEditor | update, pri save() |
poster(UploadedFile|string|null $file = null, ?string $draft = null) | static | update |
categorize(Tag|int|string|null $category) | static | update |
labels() | EventLabels | — |
tiers() | EventTiers | — |
rsvp(Model $attendee) | PendingRsvp | — |
attendees() | EventAttendees | — |
waitlist() | EventWaitlist | — |
checkIn(string $code, ?int $guests = null, bool $ignoreWindow = false) | CheckInResult | checkIn |
hosts() | EventHosts | — |
invitations() | EventInvitations | — |
transferTo(Model&Organizer $organizer, bool $keepAsHost = false) | static | transfer |
counts() | EventCounts | viewCounts |
publish() · unpublish() · complete() | static | publish · unpublish · complete |
postpone(?string $reason = null) · cancel(?string $reason = null) | static | postpone · cancel |
reschedule(CarbonInterface|string $startsAt, CarbonInterface|string|null $endsAt = null, ?string $reason = null) | static | reschedule |
moveOnline(string $url, bool $keepVenue = false) | static | moveOnline |
transition(string $name, ?string $reason = null, array $payload = []) | TransitionResult | transition |
can(string $transition) · allowedTransitions() | bool · list<string> | false / [], keď aktér nemá transition |
phase() · status() | EventPhase · EventState | — |
delete(bool $force = false) · restore() | static | delete · restore |
ics(?Model $viewer = null) | IcsCalendar | view |
jsonLd() | ?array | — |
$handle = Events::for($event);
$handle->phase(); // EventPhase — what every package rule reads
$handle->status(); // the lifecycle state (EventStatus with the shipped lifecycle)
$handle->can('cancel'); // false when the actor lacks the transition ability
$handle->allowedTransitions(); // list<string> of transition names allowed now
$handle->counts(); // EventCounts {going, interested, waitlisted, seatsLeft}
$handle->ics($viewer); // IcsCalendar
$handle->jsonLd(); // schema.org data, or nullmanager(), actor(), isSystem(), isSilent(), authorize() a context() sú verejné pre pod-handle a označené ako @internal.
Typy vstupeniek: ->tiers()
Typ vstupenky iného podujatia sa nikdy nenájde (TierNotFoundException):
| Metóda | Vracia | Oprávnenie |
|---|---|---|
make(array|string $name) | TierBuilder | manageTiers |
create(TierData $data) | AdmissionTier | manageTiers |
add(array|string $name, ?Money $price = null, ?int $capacity = null, bool $hidden = false, ?string $key = null) | AdmissionTier | manageTiers |
update(AdmissionTier|int|string $tier, UpdateTierData $data) | AdmissionTier | manageTiers |
remove($tier) · restore($tier) | EventTiers · AdmissionTier | manageTiers |
reorder(array $order) | EventTiers | manageTiers |
all() | Collection<AdmissionTier> | — (skryté len pri manageTiers) |
available() | Collection<AdmissionTier> | — (bez policy) |
Odpoveď: ->rsvp($attendee)
Účastník, ktorý odpovedá sám za seba, potrebuje rsvp; ktokoľvek, kto odpovedá za niekoho iného, potrebuje manageAttendees:
| Metóda | Vracia | Poznámky |
|---|---|---|
by(?Model $actor) | PendingRsvp | Predvolene aktér handle. |
going(AdmissionTier|int|string|null $tier = null, int $guests = 0, ?string $note = null) | Rsvp | Going, held alebo waitlisted. |
interested() · notGoing() | Rsvp | — |
Zoznam hostí: ->attendees()
Každá metóda prijme model účastníka alebo jeho Rsvp; RSVP iného podujatia sa odmietne:
| Metóda | Vracia | Oprávnenie |
|---|---|---|
add(Model $attendee, $tier = null, int $guests = 0, bool $overCapacity = false) | Rsvp | manageAttendees |
remove(Rsvp|Model $who) | EventAttendees | manageAttendees |
changeTier(Rsvp|Model $who, AdmissionTier|int|string $tier) | Rsvp | manageAttendees |
changeGuests(Rsvp|Model $who, int $guests) | Rsvp | manageAttendees |
confirm(Rsvp|Model $who, ?string $reference = null) · release(Rsvp|Model $who) | Rsvp | manageAttendees |
checkIn(Rsvp|Model $who, ?int $guests = null) · undoCheckIn(Rsvp|Model $who) | CheckInResult · EventAttendees | checkIn |
find(Model $attendee) | ?Rsvp | vlastné RSVP aktéra, inak manageAttendees |
going() · interested() · checkedIn() | Collection<Rsvp> | viewAttendees · viewInterested · checkIn |
Čakacia listina, spoluorganizátori, pozvánky a štítky
| Metóda | Vracia | Oprávnenie |
|---|---|---|
waitlist()->all() · position(Model $attendee) · promote(?int $limit = null) | Collection<Rsvp> · ?int · Collection<Rsvp> | viewWaitlist · viewWaitlist · manageAttendees |
hosts()->add(Model&Organizer $host) · remove(Model $host) | EventHosts | manageHosts |
hosts()->all() · has(Model $host) | Collection<EventHost> · bool | view |
invitations()->send(Model $invitee, ?string $message = null) | EventInvitation | invite |
invitations()->revoke(Model $invitee) · all() · pending() | EventInvitations · Collection<EventInvitation> | invite |
labels()->attach($labels) · detach($labels) · sync(iterable $labels) | EventLabels | update |
labels()->all() | Collection<Tag> | — |
Events::venues()
Nemenný: by() vráti nový prístup, ktorého zápisy overujú VenuePolicy:
| Metóda | Vracia | Policy (s aktérom) |
|---|---|---|
by(?Model $actor) | Venues | Pripíše create, update, delete, restore, geocode a builder aktérovi $actor. |
make(array|string $name) | VenueBuilder | Nesie aktéra prístupu. |
create(VenueData $data) | Venue | create (+ manageShared bez vlastníka, alebo vlastník musí aktéra povoliť); DTO s iným aktérom ako by() sa odmietne. |
update(Venue $venue, UpdateVenueData $data) | Venue | update |
delete(Venue $venue) · restore(Venue $venue) | void · Venue | delete — odmietne sa (venue_in_use), kým ho používa neskončené podujatie · restore |
geocode(Venue $venue, bool $force = false) | Venue | geocode; len chýbajúce súradnice, ak nie je $force. |
find(int $id) · ownedBy(Model $owner) · near(Coordinates $point, float $km) | ?Venue · Builder<Venue> | Dotazy, bez policy. |
Events::rsvps()
| Metóda | Vracia | Poznámky |
|---|---|---|
by(?Model $actor) | Rsvps | confirm, release a rotateCode potom overia manageAttendees; requestPayment pustí aj vlastného účastníka RSVP. |
confirmPayment(string $reference) | Rsvp | Webhook vašej platby: held → going, idempotentné; bez policy. |
confirm(Rsvp $rsvp, ?string $reference = null) | Rsvp | Rezervované RSVP, ručne. |
release(Rsvp $rsvp) | Rsvp | Vráti rezervované miesta hneď. |
rotateCode(Rsvp $rsvp) | Rsvp | Nový kód pre check-in; starý prestane fungovať. |
qr(Rsvp $rsvp, ?QrOptions $options = null) | ?Qr\ValueObjects\Svg | Kód ako inline SVG; null, ak kód nie je. |
findByCode(string $code) | ?Rsvp | RSVP za kódom alebo za vstupom zo skenera, ktorý kód obsahuje. |
requestPayment(Rsvp $rsvp) | ?PaymentRequest | Požiada collector (znova) o checkout pre rezervované RSVP. |
Events::invitations()
| Metóda | Vracia | Poznámky |
|---|---|---|
asSystem() | Invitations | Dôveryhodný kód: odpovedá za akéhokoľvek pozvaného. |
accept(string $token, RsvpResponse $as = RsvpResponse::Going, ?Model $by = null) | Rsvp | Vytvorí RSVP pozvaného (going alebo interested). |
decline(string $token, ?Model $by = null) | EventInvitation | — |
find(string $token) | ?EventInvitation | Platná pozvánka alebo null. |
Ako $by odovzdajte používateľa z požiadavky: pozvaný s účtom odpovedá len prihlásený ako on sám.
Builder podujatia
Events::make($title) vráti EventBuilder. Settery si uložia, čo dostanú, a harmonogram vyriešia až pri create(), keď je známe časové pásmo, takže ich poradie nikdy nezmení výsledný okamih; tam, kde to ide, validujú hneď:
| Setter | Poznámky |
|---|---|
description(array|string $description) | — |
slug(array $slug) | Ručné slugy pre jazyky; obsadený vyhodí invalid_event (nikdy sa nepridá prípona). |
organizedBy(Model&Organizer $organizer) | Povinné. |
coHostedBy(Model&Organizer ...$hosts) | Pridá do zoznamu. |
at(Venue|int|null $venue) | Model alebo jeho id. |
online(?string $url) | http(s), ≤ 2048 znakov; uloží sa šifrovane. |
attendanceMode(AttendanceMode $mode) | Musí zodpovedať miestu konania a odkazu. |
timezone(string $timezone) | Názov IANA. |
startsAt() · endsAt() · duration() | startsAt zruší celodenný rozsah, endsAt trvanie, duration koniec; duration prijme 'PT3H', '3 hours' alebo CarbonInterval. |
allDay(string $from, ?string $through = null) | Miestne dni Y-m-d, $through vrátane. |
doorsOpenAt(CarbonInterface|string $doorsOpenAt) | V rámci 12 hodín pred začiatkom. |
visibility(Visibility $visibility) · unlisted() · private() | — |
capacity(?int $capacity) · maxGuests(int $guests) | Kapacita null = bez obmedzenia. |
waitlist(bool $on = true, bool $autoPromote = true) | — |
rsvpWindow($opensAt = null, $closesAt = null) | — |
guestList(GuestList $guestList) · showCounts(bool $show = true) | — |
poster(UploadedFile|string|null $file = null, ?string $draft = null) | — |
category(Tag|int|string|null $category) · labels(iterable $labels) | — |
tier(array|string $name, ?Money $price = null, ?int $capacity = null, bool $hidden = false, ?string $key = null) | Opakovateľné. |
reminders(?array $offsets) | ≤ 5 posunov ISO-8601, PT5M–P31D. |
meta(array $meta) | Súkromné: API ich nikdy nevykreslí. |
by(?Model $actor) | Overí create a či organizátor aktéra povoľuje. |
toData() · create() · publish() | CreateEventData · koncept · vytvorenie a zverejnenie v jednej transakcii. |
Events::for($event)->edit() vráti EventEditor s rovnakými settermi pre existujúce podujatie a navyše title(): zmenia sa len polia, ktorých sa dotknete, save() spustí update() na handle a toData() vráti UpdateEventData. Slug, kategória, štítky, typy vstupeniek, plagát a spoluorganizátori majú vlastné metódy handle. Builder typu vstupenky a builder miesta konania opisujú ich vlastné stránky.
Traity modelov
| Člen AttendsEvents | Poznámky |
|---|---|
rsvp(Event $event): PendingRsvp | $user->rsvp($event)->going() — cez manažér, takže ho fake zaznamená. |
isGoingTo(Event $event): bool · rsvpFor(Event $event): ?Rsvp | — |
eventRsvps(): MorphMany | Všetky RSVP modelu. |
attendingEvents() · interestingEvents(): MorphToMany | Podujatia, na ktoré ide / o ktoré má záujem. |
eventFeed(bool $includePrivate = false): IcsCalendar | Jeho osobný kalendár. |
| deletion hook | Trvalé zmazanie (alebo zmazanie bez soft delete) uvoľní jeho RSVP: miesta sa vrátia, čakacia listina sa posunie, riadky sa odstránia. |
OrganizesEvents implementuje kontrakt Organizer s predvolenými hodnotami a pridáva organizedEvents(), coHostedEvents() a organizeEvent($title) — pozrite Organizátori, spoluorganizátori a pozvánky. Oba traity idú cez manažér, takže Events::fake() zaznamená, čo robia.
PHP API dôveruje volajúcemu
Fasáda vždy vynucuje doménové pravidlá — miesta, okná, fázy, pozvánky, limity skupiny. Policy sa pýta, len keď cez by() uvediete aktéra. V kontroléri preto vždy odovzdajte prihláseného používateľa: handle bez by() skopírovaný do kontroléra pri vstupe by dovolil ktorémukoľvek prihlásenému používateľovi urobiť check-in komukoľvek.
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.