Kalendáre, feedy a JSON-LD
Kalendárové súbory
return Events::for($event)->ics($request->user()); // one event; the join link only if this viewer may see it
return Events::ics($events, $request->user()); // a list: events the viewer may not see are skipped
return Events::feeds()->public(new EventFeedQuery(category: 'jazz'));
return $user->eventFeed(); // = Events::feeds()->for($user)
// In a Mailable's attachments(): Attachment::fromData(fn () => $ics, 'event.ics')->withMime('text/calendar')
$ics = (string) Events::for($event)->ics($user);Každý vstup vráti Calendar\IcsCalendar — Responsable (text/calendar; charset=utf-8, upravený názov súboru, attachment pre podujatie a inline pre feed) aj Stringable. Názov súboru je slug verejného podujatia (inak jeho uuid) + .ics, events.ics pre zoznam alebo verejný feed a my-events.ics pre osobný feed. Divák, ktorý podujatie vidieť nesmie, nedostane nič: zoznam ho vynechá a ics($viewer) jedného podujatia vyhodí jednotnú EventNotFoundException. Bez diváka a bez aktéra by() je ics() dôveryhodné PHP: podujatie vykreslí (nikdy koncept), no nikdy nie odkaz na pripojenie.
Čo nesie každé podujatie
- UID ({uuid}@{hostiteľ aplikácie}), DTSTAMP, LAST-MODIFIED a SEQUENCE — zvyšuje ho každá zmena stavu a každá zmena času, miesta či odkazu a aj zmena názvu, adresy alebo súradníc miesta pri jeho neskončených podujatiach, takže odoberané kalendáre sa aktualizujú.
- DTSTART a DTEND v UTC — pri celodenných podujatiach VALUE=DATE s výlučným dňom konca.
- SUMMARY, DESCRIPTION (a odkaz na pripojenie pre diváka, ktorý ho smie vidieť), LOCATION (názov a adresa miesta, alebo odkaz na pripojenie pri online podujatí, ku ktorému sa divák smie pripojiť), GEO, URL a CATEGORIES (kategória a štítky).
- STATUS: CONFIRMED; odložené podujatie je TENTATIVE, zrušené CANCELLED.
- ORGANIZER;CN=…:mailto:… len vtedy, keď organizátor ponúka eventOrganizerEmail(). Riadky ATTENDEE nie sú nikdy a koncepty sa nikdy neexportujú.
- Text je escapovaný podľa RFC 5545, parametre sú upravené a v úvodzovkách a riadky sa zalamujú po 75 oktetoch bez rozdelenia znaku UTF-8 — názvy ani popisy nemôžu podstrčiť vlastnosti.
Feedy
use RoundlyConsulting\Events\DataTransferObjects\EventFeedQuery;
Route::get('/calendars/jazz.ics', fn () => Events::feeds()->public(new EventFeedQuery(
category: 'jazz', label: 'live', organizer: $club, venue: $venue, name: 'Jazz at the club',
)));- Events::feeds()->public(EventFeedQuery $query) obsahuje verejne uvedené podujatia, ktoré ešte neskončili — naplánované, odložené, presunuté —, a k nim zrušené v rámci events.feeds.keep_cancelled_for (P30D), aby odoberané kalendáre dostali zrušenie. Filtruje podľa kategórie (vrátane podkategórií), štítka (ktoréhokoľvek), organizátora a miesta konania, radí podľa začiatku, končí pri events.feeds.max_events a nikdy nenesie odkaz na pripojenie. Kalendár sa volá podľa name z dotazu, inak events.feeds.name, a obnovuje sa každú hodinu.
- Events::feeds()->for($attendee, includePrivate: false) — alebo $attendee->eventFeed() — obsahuje ohlásené podujatia, na ktoré účastník ide, aj s odkazmi na pripojenie, ktoré skončili najviac pred keep_cancelled_for; súkromné len na požiadanie. Je len v PHP: poskytujte ho za vlastnou URL s tokenom.
- API poskytuje verejný feed na GET /api/events/feed.ics a jedno podujatie na GET /api/events/{event}/calendar.ics.
JSON-LD pre vyhľadávače
@push('head')
@eventJsonLd($event) {{-- the script tag, or nothing for unlisted, private and draft events --}}
@endpushEvents::jsonLd($event); // the array, or null
Events::for($event)->jsonLd();
$event->toJsonLd();
$event->renderJsonLd(); // HtmlString: the script tag, or emptyGeneruje sa pre verejné podujatia po fáze Draft — pre podujatia len cez odkaz pri events.seo.json_ld.unlisted, pre súkromné nikdy — v aktuálnom jazyku. View escapuje lomené zátvorky, ampersandy aj úvodzovky na hex, takže názov nikdy neuzavrie značku script. Jazz Night z README — bez plagátu a s tímom Blue Note Club ako organizátorom — sa vykreslí takto:
{
"@context": "https://schema.org",
"@type": "Event",
"name": "Jazz Night",
"description": "A live quartet, then an open jam session.",
"startDate": "2026-11-14T20:00:00+01:00",
"endDate": "2026-11-14T23:00:00+01:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "Blue Note",
"address": {
"@type": "PostalAddress",
"streetAddress": "Hlavná 1",
"addressLocality": "Bratislava",
"postalCode": "811 01",
"addressCountry": "SK"
},
"geo": { "@type": "GeoCoordinates", "latitude": 48.1439, "longitude": 17.1097 }
},
"offers": [
{
"@type": "Offer",
"name": "Free entry",
"price": "0",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"url": "https://example.com/en/events/jazz-night"
},
{
"@type": "Offer",
"name": "Supporter",
"price": "15.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"url": "https://example.com/en/events/jazz-night"
}
],
"organizer": { "@type": "Organization", "name": "Blue Note Club" },
"keywords": "Live, Late night",
"url": "https://example.com/en/events/jazz-night"
}- startDate a endDate nesú vlastný posun podujatia voči UTC — pri celodenných podujatiach len dátum s posledným dňom vrátane — a k tomu doorTime.
- eventStatus: EventScheduled (EventMovedOnline pri ohlásenom podujatí, ktoré prešlo online), EventPostponed, EventRescheduled s previousStartDate alebo EventCancelled so zachovanými dátumami; ukončené podujatie zostáva EventScheduled. Seo\EventJsonLd::status($event) vráti len názov stavu — schema_status v API.
- location je Place (názov, PostalAddress, GeoCoordinates) a/alebo VirtualLocation s URL stránky podujatia — odkaz na pripojenie len pri events.seo.json_ld.expose_online_url.
- image obsahuje varianty plagátu square, landscape a wide; description je čistý text s najviac 300 znakmi.
- offers má jednu Offer na každý viditeľný typ vstupenky — price ako desatinný reťazec (0, ak je zadarmo), priceCurrency, availability InStock, SoldOut (žiadne voľné miesta alebo skončený predaj) či PreOrder pred začiatkom predaja, validFrom, validThrough a url — alebo jednu bezplatnú ponuku pre podujatie bez typov vstupeniek (SoldOut, keď je plné a nemá čakaciu listinu).
- organizer je Organization alebo Person podľa events.seo.json_ld.organizer_type; keywords sú názvy štítkov.
URL
Contracts\EventUrls určuje odkazy v JSON-LD, kalendárových súboroch a notifikáciách — event(), invitation($token) a rsvp($rsvp), každý ?string. Predvolený Support\TemplateEventUrls vyplní šablóny events.urls.* zástupnými hodnotami kódovanými pre URL a prázdna šablóna znamená žiadny odkaz. Podujatia len cez odkaz a súkromné používajú events.urls.event_link ({uuid}); keď je prázdny, urls.event sa použije len vtedy, ak neobsahuje {slug} — odkaz so slugom by práve ľuďom, ktorým bol poslaný, vrátil 404. Ak chcete volať route(), naviažte vlastnú triedu:
use RoundlyConsulting\Events\Contracts\EventUrls;
use RoundlyConsulting\Events\Models\Event;
use RoundlyConsulting\Events\Models\Rsvp;
final class AppEventUrls implements EventUrls
{
public function event(Event $event): ?string
{
return route('meetups.show', $event->uuid);
}
public function invitation(string $token): ?string
{
return route('meetups.invitation', $token);
}
public function rsvp(Rsvp $rsvp): ?string
{
return route('meetups.ticket', [$rsvp->event->uuid, $rsvp->getKey()]);
}
}
// config/events.php — 'urls' => ['resolver' => AppEventUrls::class, …]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.